1주차 교육 예제는 !!
대한약사회에서 운영하는 휴일지킴이약국이라는 사이트를 통해 약국 정보 추출 입니다
해당 사이트에서 약국 리스트를 추출하기 위해서 해야하는 단계는 아래와 같다.
혼자 하는 생각 - 활용, 재가공하여 사용하지말자
제5조 (게시물의 저작권)
휴일지킴이약국 홈페이지(www.pharm114.or.kr)에서 제공되는 "휴일지킴이약국정보"는 국민의 의약품 접근성 확대를 위해 "약사회"
에서 제공하는 정보입니다.
다만, "휴일지킴이약국정보"의 수집, 가공, 이용 등 관리에 대한 저작권은 게시자인 "약사회"에 있으므로 게시된 정보 및 검색
결과를 수집하여 획득한 데이터를 게시자의 사전동의 없이 영리 또는 비영리 목적으로 활용 또는 재가공하여 사용할 수
없습니다.
사이트에 접속해서 페이지 소스를 보면 ul 태그 아래 시,도가 리스트로 쭉 나와있다. class가 있기 때문에 해당 리스트를 뽑아 활용 가능할 듯 한데, 지금 당장의 목표는 시도,군구 까지 내가 지정하면 클릭해서 들어가는 정도이다.
const evalCode = async function () {
await page.evaluate(function (sido) {
document.querySelector(`#continents > li.${sido} > a`).click();
}, sido);
};
page.evaluate()
를 통해 브라우저 콘솔에다가 document
를 이용한 명령어를 보낼 수 있다.
const evalCity = async function () {
//해당 엘리먼트를 찾을 때까지 기다림
await page.waitForSelector(`#container #continents > li.${sigungu} > a`);
await page.evaluate(function (sigungu) {
document
.querySelector(`#container #continents > li.${sigungu} > a`)
.click();
}, sigungu);
};
페이지 로딩 중에 바로 evaluate 하면 오류가 발생한다. waitForSelector를 이용해 해당 엘리먼트를 찾을 때 까지 기다릴 수 있다.
const pageSelector = '원하는 태그 부모 선택자'
let pageLength = 0;
const getPageLength = async function () {
await page.waitForSelector(pageSelector);
pageLength = await page.evaluate(function (pageSelector) {
const result = document.querySelector(pageSelector).children.length;
return result;
}, pageSelector);
};
해당 사이트를 확인해보면 각 페이지는 <td>
태그 안에서 <a>
가 나열되어있는 형태이다.
따라서 페이지 개수를 확인하기 위해서는 부모 태그를 선택하여 자식 태그의 수를 확인하면 된다.
이후 getData()
에서도 page 관련 선택자를 사용하여 이동해야하기때문에 const 변수로 사전에 미리 선언해두었다.
const getData = async function () {
//페이지 loop
for (let i = 1; i <= pageLength; i++) {
await page.waitForSelector(pageSelector);
const infoArr = await page.evaluate(
function (i, sido, sigungu) {
//약국 정보 테이블의 각 열을 뽑아오는 구문
var trArrr = document.querySelectorAll(
"#printZone > table:nth-child(2) > tbody tr"
);
var returnData = [];
for (var i = 0; i < trArrr.length; i++) {
var currentTr = trArrr[i];
var name = currentTr
.querySelector("td")
?.innerText.replaceAll("\n", "")
.replaceAll("\t", "");
var address = currentTr
.querySelectorAll("td")[2]
?.innerText.replaceAll("\n", "")
.replaceAll("\t", "");
var tel = currentTr
.querySelectorAll("td")[3]
?.innerText.replaceAll("\n", "")
.replaceAll("\t", "");
var open = currentTr
.querySelectorAll("td")[4]
?.innerText.replaceAll("\n", "")
.replaceAll("\t", "");
var jsonData = {
name,
address,
tel,
sido,
sigungu,
open, //변수와 이름 같으면 생략 가능
};
if (jsonData.address != undefined) {
returnData.push(jsonData);
}
}
return returnData;
},
i,
sigungu,
sido
);
finalData = finalData.concat(infoArr);
console.log(finalData.length);
if (pageLength != i) {
await page.evaluate(
function (i, pageSelector) {
document.querySelector(pageSelector).children[i].click();
},
i,
pageSelector
);
}
}
browser.close();
};
const writeFile = async function () {
const stringData = JSON.stringify(finalData);
const exist = fs.existsSync(`./json/${sido}`);
if (!exist) {
fs.mkdir(`./json/${sido}`, { recursive: true }, function (err) {
console.log(err);
});
}
const filePath = `./json/${sido}/${sigungu}.json`;
await fs.writeFileSync(filePath, stringData);
};
🎉 실행결과
데이터가 제대로 추출되어 JSON 파일로 저장이 되었다!