자바스크립트 크롤링 및 DB 저장
안녕하세요. 프로젝트를 하면서 웹 페이지 크롤링을 구현하게 되었습니다. 크롤링이란 웹 페이지를 가져와서 데이터를 추출하는 것을 의미하는데요. 이에 대한 설명과 함께 데이터를 DB 에 어떻게 저장할 수 있는 지, 시도하면서 발생했던 이슈들을 가지고 포스팅을 진행하려고 합니다.
크롤링 데이터는 '서울 거리예술 축제' 홈페이지에서 가져왔습니다.
크롤링, 스크랩핑을 할 때 자바스크립트 cheerio 모듈을 사용하였습니다. 노드에 이렇게 좋은 기능들이 많은 거 보면, 감사하기도 하고 정말 대단한 개발자 분들이 많이 계시는구나를 느끼게 됩니다.
사용했던 또 다른 모듈은 HTTP 네트워크 라이브러리인 request 입니다. 크롤링 시 사용할 url 을 저장시켜주었구요.
request 요청의 결과로 받아오는 값을 객체로 저장하였고, 구분하는 방법은 웹페이지 html 태그의 className 을 이용하였습니다.
request(url, function(error, response, html){if (!error) {var $ = cheerio.load(html);for(var i = -2; i < 17;){$('.tit').each(function(){var place_info = $(this);var place_info_text = place_info.text();//console.log(place_info_text);//place[i] = place_info_text;result['place'][i] = place_info_text;i++;})}
받아오는 데이터가 한 프로퍼티 당 33개 정도 되었는데, 이상하게 갯수를 맞춰주면 중복 데이터가 쌓이는 이슈가 있어서 필요한 데이터 수에 맞게 코드를 수정하였습니다.
이 저장된 객체는 외부의 파일에서 사용하려고 생각하였기 때문에 module.exports 로 넘겨주었습니다.
그러나 외부 파일 (app.js) 에서 이 객체를 가져올 때 undefined 로 표시되는 것이 문제였습니다. 값이 저장되지 않은 채로 객체를 사용했던 것이었습니다.
이를 해결하기 위해서 Promise 를 사용하였습니다. 비동기 처리를 할 때 많이 사용하는 인스턴스 이죠. 타이밍을 맞추는 시도를 하였습니다. 크롤링 데이터가 넘어오지 않은 상태인데, 자바스크립트의 동기적인 특성으로 해당 객체를 비어 있는 채로 종료를 시킨 것입니다.
크롤링 해오는 파일의 함수를 Promise 를 리턴하는 형태로 변경하였습니다.
var requestFn = () =>new Promise((resolve, reject) => {... // resolve 에 사용하고자 하는 객체를 인자로 넣었습니다.
Promise 속성으로 이후에 .then() 메소드에는 resolve 인자의 값이 전달됩니다.
전달받은 데이터를 시퀄라이즈를 사용해서 테이블 칼럼 값으로 저장하는 것입니다. 사실 DB 에 저장하는 부분은 (.create) 를 이용하는 것인데, 말 그대로 라서 덧붙일 것이 없을 거 같습니다.
그리고, 한 가지 더 생각했던 것은 이미 데이터가 들어가 있는 경우 다시 insert 를 하지 않는 것입니다. 이를 체크하는 함수 하나를 만들었습니다.
function testNumChk() {return new Promise((resolve, reject) => {test.findAll().then(result => {if (result.length !== 0) {//console.log(result);chkBoolean = true;resolve(chkBoolean);} else {resolve(chkBoolean);}}).catch(error => {res.status(500).send(error);})})}
객체에 데이터가 있는 경우에는 Boolean = true 로 값을 바꿔주어서, true 인 경우 더 이상 insert 되지 않도록 한 것입니다.
이를 통해 DB에 중복 데이터가 생기는 것을 방지하였습니다.
이상으로 웹페이지 크롤링 과 이를 DB 에 저장하는 방법에 대한 포스팅을 마치도록 하겠습니다. 감사합니다.
