지난번에 작성했던 코드로는 계속된 오류가 발생했다.
혹시나 API key 가 더이상 동작을 안하는 가 해서 새로 발급을 받고, ec2를 재부팅 했으나 오류는 계속 진행되었다.
여러번 새로고침을 하면 가끔씩 데이터가 나오긴 했지만, 가끔씩이였었다.
그래서 자꾸 읽어오지 못하는 오류가 발생함... (개짜증)
결국 다른 방법을 사용해야 했다. 선별진료소 목록의 신뢰성을 높이기위해 보건복지부 홈페이지의 선별진료소 리스트를 긁어오기로 했다.
사용한 모듈은 axios와 cheerio 를 새롭게 사용했다.
npm install axios cheerio
우선 모듈을 다운로드 받아주었다.
var axios = require('axios');
var cheerio = require('cheerio');
코드에 두줄을 추가해주었다.
- axios : 사이트의 HTML를 Node환경으로 가져오기 위한 라이브러리이다.
- cheerio : Node 환경에서 jQuery처럼 html의 태그를 선택하는 기능을 사용하기 위한 라이브러리이다.
기존에 그때 그때 api 를 받아와서 kakao local API를 통해 병원이름을 위도,경도로 나타내 주려 했지만 하루에 한번씩 업데이트 되기에 비효율적이라 생각했고, DB에 저장해서 사용하기로 했다.
크롤링의 시작
보건복지부 선별진료소 목록페이지를 보면 병원의 목록이 20개씩 30페이지로 생성되어있다.
각 페이지를 다 크롤링해야 하기에 함수를 만들어서 for문을 돌리기로 하였다.
처음 async와 await의 동작을 제대로 이해하지 못했을때는 자꾸만 undefined가 반환되어서 고생했다.
홈페이지에 접속하여 F12(개발자 도구)를 켜준다.(chrome 기준)
왼쪽 위에 마우스 표시를 선택하고 수집을 원하는 데이터에 클릭을 해주면 다음과 같이 그 위치의 HTML로 이동할 수 있다.
내 경우는 table.co_tb_base 속 tbody.tb_center 속 tr 의 데이터들을 확인 해야한다.
이 태그들을 토대로 코드를 작성했다.
const getHtml = async number => {
console.log(number + "번째 함수 응답");
await axios.get(`https://www.mohw.go.kr/react/ncov/selclinic04ls.jsp?page=${number}`).then(html => {
const $ = cheerio.load(html.data);
const $bodyList = $("table.co_tb_base tbody.tb_center").children("tr");
$bodyList.each(async function(i, elem) {
if ($(this).find('td.name strong').text()) {
await findStar($(this).find('td.name strong').text()) + '<br>';
} else {
console.log("ㄴㄴ");
}
}); // each -- end
if (number === 30) {
res.redirect('/hospital_check');
}
}); // then -- end
}; // getHtml -- end
for (var i = 1; i <= 30; i++) {
console.log(i + "번째 함수 호출");
await getHtml(i);
}
간략한 코드설명으로 getHtml 함수는 number라는 인자를 받아온다.
받아온 인자로 원하는 페이지에 접근해 axios.get 함수를 통해서 페이지의 html을 서버로 읽어온다.
이후 cheerio 라이브러리를 이용해서 데이터를 추출한다.
HTML 속 태그들을 선택하기 위해 먼저 찾았던 태그들의 이름을 작성해준다.
나는 tr 태그속의 데이터를 추출해야 하기에 children("tr")을 통해 앞의 태그속 tr의 데이터를 배열로 모두 가져온다.
그 속에서 배열을 처음부터 돌면서 추출을 원하는 td.name strong 을 text 형식으로 받아온다.
(findStar함수는 이후 데이터가 '강남구보건소*(검체채취 가능)' 과 같이 길게 나오기에 *이하를 삭제하기 위해 만들었다.)
이와같이 데이터를 받아올수 있다. await와 async를 사용하지 않았기에 자꾸만 undefind가 반환되는 바람에 고생했다.
아, findStar의 코드는 다음과 같다.
const findStar = async str => {
if (str.indexOf('*') !== -1) {
str = str.substr(0, str.indexOf('*'));
}
return str;
}; // findStar -- end
입력받은 스트링에서 *의 인덱스를 찾은다음, 처음부터 *까지의 문자열을 잘라서 사용했다.
- str.indexOf (a) : str속의 a의 인덱스를 리턴해준다. 없을 시에는 -1을 리턴
- str.substr(a,b) : str 속에서 a에서부터 b개의 문자열을 잘라서 리턴한다.
*이하의 값을 삭제할수 있어서 깔끔한 데이터를 받을 수 있다.
kakao local api 사용과 db 연결까지 끝마치려 했으나, async와 await의 압박으로 다음에 이어서 작성해야겠다.
'Javascript > Node.js' 카테고리의 다른 글
DocumentDB Connect in Local PC ( MAC OS ) (0) | 2021.06.18 |
---|---|
NPM node-schedule (0) | 2021.06.18 |
# 공공 API를 통해 카카오 지도에 선별진료소 표기하기 - (3) (0) | 2020.10.12 |
공공 API를 통해 카카오 지도에 선별진료소 표기하기 - (1) (0) | 2020.10.07 |