안녕하세요.
오늘은 번외로 실용적인 내용을 준비했습니다.
목차
크롤링이 필요한 이유
아끼는 대학 후배를 오랜만에 만났는데 한 웹사이트에서 검색을 하여 수백 건에 이르는 결과를 일일이 한 땀 한 땀 엑셀에 붙여넣는 노가다성 작업을 한다면서 힘들어 하더라구요.
그 말을 듣고 제가 가만히 있을 수는 없었죠.
어떻게든 한방에 할 수 있는 방법을 찾아보겠다고 호언장담을 했습니다.
크롤링이란
사실 크롤링이라는 용어는 잘 몰랐는데 들어보니 저는 스크래핑으로 알고 있었던 기술이었어요.
보통 이 두 가지 용어를 혼용해서 쓰는거 같아요.
간단히 말하면 웹페이지 내용을 그대로 읽어와서 원하는 내용을 추출하는 작업인데요.
어떻게 사용하느냐에 따라 굉장히 유용한 결과물을 얻어낼 수 있어 보입니다.
크롤링을 위한 사전 준비
이 분야에서는 보통 파이썬(Python)이 많이 쓰인다고 하네요.
아무래도 비전공자들이 사용하기 쉽고 제공하는 라이브러리도 많은 언어라서 그런거 같아요.
그런데 저는 파이썬을 다뤄 본 적이 많지 않아서 JavaScript를 이용하여 작업을 했습니다.
조만간 파이썬으로도 하는 방법을 정리해서 게시하도록 해볼게요. :)
+내용 추가 (2020.09.01)
약속 지켰습니다 ㅎㅎ
이 내용은 관심있는 분만 보시면 됩니다.
nodeJS 및 필요 모듈 설치
먼저 nodeJS가 필요합니다.
설치 방법을 잘 모르시겠다면
링크를 하나 남겨 놓을테니 참고하시면 되구요.
서버까지 띄우실 필요는 없어요.
그 다음으로 axios, cheerio 라는 두 가지 모듈은 설치하셔야 됩니다.
터미널 작업할 디렉토리에서 npm 명령어를 이용하여 다음과 같이 입력하세요.
npm i axios cheerio
axios는 URL을 호출하여 웹페이지 HTML을 그대로 가져와 Promise 형태로 반환하는 모듈입니다.
자세한 사항은 아래 참고하시면 되구요.
cheerio는 HTML DOM 형태의 데이터에서 원하는 내용을 쉽게 추출할 수 있게 해주는 기능을 가진 모듈이에요.
더 궁금하신 사항은 아래 링크에서 확인하시면 됩니다.
크롤링 코드 작성
이제 코드를 작성해 보겠습니다.
먼저 위에서 설치했던 모듈을 포함하여 아래와 같이 세 가지 모듈을 불러옵니다.
const axios = require("axios");
const cheerio = require("cheerio");
const fs = require('fs');
fs는 파일시스템 모듈로 nodeJS 기본 제공 모듈입니다.
텍스트 파일을 읽고 쓰기 위해 사용합니다.
그 다음 필요 전역 변수를 선언해줍니다.
var resultList = [];
var cnt = 0;
결과 데이터를 저장할 배열 변수 및 마지막에 파일로 쓰기 위해 카운팅 변수를 하나 선언했습니다.
다음으로 URL을 호출하여 HTML 데이터를 받아오는 함수 하나를 정의합니다.
function delay(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve();
},ms);
});
}
function getHTML(url) {
return new Promise(resolve=>{
delay(300).then(function() {
axios.get(url).then(function(data) {
resolve(data);
});
});
})
}
axios 모듈을 이용하여 입력받은 URL을 호출하여 HTML 데이터를 그대로 받아오는 기능을 구현했는데요.
여러 건 호출할 경우를 대비하여 0.3초 간격으로 호출되도록 구현하였습니다.
그리고 실습해 볼 샘플 파일을 하나 가져왔습니다.
아래와 같이 크롤링에 필요한 URL 정보가 다수 담겨 있습니다.
이제 본격적으로 메인 함수를 구현하겠습니다.
function main() {
fs.readFile('sample.txt','utf8',function(err, data){
var allText = data;
var list = allText.split('\n');
var workList = [];
for(var i=1; i<list.length-1;i++){
workList.push(list[i].split('^')[4]);
}
makeJSON(workList); // 아직 미구현
});
}
main();
fs 모듈을 이용하여 같은 경로에 있는 sample.txt 파일을 읽어옵니다.
먼저 읽어온 내용을 개행문자(\n) 기준으로 나누어 리스트로 만들었습니다.
그리고 다시 각각을 구분기호(^) 기준으로 나누어 마지막에 있는 URL 정보만 workList 변수에 배열로 저장하였습니다.
그리고 makeJSON 함수를 만들어서 제귀 호출을 할 예정입니다.
정제한 URL 정보로 앞서 정의한 함수를 호출하여 HTML 데이터를 가져와 보겠습니다.
function makeJSON(workList) {
getHTML(workList[cnt]).then(html => {
let result = {};
const $ = cheerio.load(html.data);
result['title'] = $("body").find(".search_tit").text();
result['date'] = $("body").find(".tit_loc").text();
result['content_trans'] = $("body").find(".ins_view_pd").find(".paragraph").eq(0).text();
result['content_origin'] = $("body").find(".ins_view_pd").find(".paragraph").eq(1).text();
return result;
})
}
먼저 workList 배열을 인자로 받는 makeJSON 함수를 만듭니다.
사이트에 직접 들어가 HTML 소스를 분석해 본 결과 제목은 search_tit, 날짜는 tit_loc, 본문 내용은 ins_view_pd 라는 class를 이용하고 있는 것을 확인할 수 있었습니다. 본문은 다시 번역문과 원문으로 나뉘는데 서로 같은 클래스를 이용하고 있어서 인덱스로 구분하였습니다. 그리고 그 안에서 실제 필요한 내용은 다시 paragraph 이름의 class를 가지고 있는 부분이었습니다. 그에 따라 cheerio 모듈을 이용하여 데이터를 분리하였고 JSON 형태로 값을 담았습니다.
이제 결과를 파일로 저장하는 일만 남았습니다.
function makeJSON(workList) {
getHTML(workList[cnt]).then(html => {
let result = {};
const $ = cheerio.load(html.data);
result['title'] = $("body").find(".search_tit").text();
result['date'] = $("body").find(".tit_loc").text();
result['content_trans'] = $("body").find(".ins_view_pd").find(".paragraph").eq(0).text();
result['content_origin'] = $("body").find(".ins_view_pd").find(".paragraph").eq(1).text();
return result;
})
// 추가 작성
.then(res => {
cnt++;
resultList.push(res);
if(workList.length == cnt){
fs.writeFile('result_json.txt', JSON.stringify(resultList), 'utf8', function(error){
console.log('write end');
});
} else {
makeJSON(workList);
}
console.log(cnt);
});
}
호출할 URL이 여러 건인 경우 0.3초 간격으로 제귀 호출이 됩니다.
cnt 변수를 하나씩 증가하면서 작업을 하며 마지막 결과를 받았을 경우 모든 결과를 한 번에 파일로 저장을 하고 작업이 종료됩니다. 이 경우에도 파일 저장에 fs 모듈이 사용되었습니다.
전체 소스
최종 점검을 위해 전체 소스를 제공합니다.
const axios = require("axios");
const cheerio = require("cheerio");
const fs = require('fs');
var resultList = [];
var cnt = 0;
function delay(ms) {
return new Promise(function(resolve, reject) {
setTimeout(function(){
resolve();
},ms);
});
}
function getHTML(url) {
return new Promise(resolve=>{
delay(300).then(function() {
axios.get(url).then(function(data) {
resolve(data);
});
});
})
}
function makeJSON(workList) {
getHTML(workList[cnt]).then(html => {
let result = {};
const $ = cheerio.load(html.data);
result['title'] = $("body").find(".search_tit").text();
result['date'] = $("body").find(".tit_loc").text();
result['content_trans'] = $("body").find(".ins_view_pd").find(".paragraph").eq(0).text();
result['content_origin'] = $("body").find(".ins_view_pd").find(".paragraph").eq(1).text();
return result;
})
// 추가 작성
.then(res => {
cnt++;
resultList.push(res);
if(workList.length == cnt){
fs.writeFile('result_json.txt', JSON.stringify(resultList), 'utf8', function(error){
console.log('write end');
});
} else {
makeJSON(workList);
}
console.log(cnt);
});
}
function main() {
fs.readFile('sample.txt','utf8',function(err, data){
var allText = data;
var list = allText.split('\n');
var workList = [];
for(var i=1; i<list.length-1;i++){
workList.push(list[i].split('^')[4]);
}
makeJSON(workList);
});
}
main();
작성한 내용은 crawling.js로 저장하겠습니다.
그리고 터미널에서 아래와 같이 실행해 줍니다.
node crawling.js
결과 확인
작업이 완료되면 같은 경로에 result_json.txt 파일이 생성된 것을 확인할 수 있습니다.
생성된 파일을 메모장으로 열어보니
이와 같은 형태로 데이터가 잘 저장된 것을 볼 수 있었습니다.
이처럼 JSON 형태로 저장을 하면 원하는대로 가공하여 여러 방면에 활용할 수 있어보입니다.
그럼 다음에는 파이썬으로 크롤링 하는 방법도 알아보도록 하겠습니다.
감사합니다.
↓↓파이썬을 활용한 크롤링 모음↓↓
파이썬 크롤링을 이용하여 인스타그램 맞팔 여부 자동 확인하기
'코딩 강의 > 유용한 스킬 없을까요' 카테고리의 다른 글
비트코인 암호 화폐 거래소 업비트 API(파이썬)를 활용한 변동성 돌파 전략 구현 방법 (돌파 계수 = 노이즈 비율) (1) | 2021.06.17 |
---|---|
프로그램 매매 핵심 지표, 이동평균선 구하는 방법 (암호 화폐) (1) | 2021.06.11 |
pyupbit 라이브러리를 통한 비트코인 암호 화폐 거래소 API(파이썬) 사용 방법 (1) | 2021.06.10 |
비트코인 암호 화폐 거래소 업비트 API(파이썬) 사용 방법 (6) | 2021.05.16 |
파이썬 크롤링으로 URL 이미지 저장하기 (0) | 2020.10.29 |
파이썬 텍스트 크롤링 따라하기 (2) | 2020.09.01 |
파이썬 크롤링을 이용하여 인스타그램 맞팔 여부 자동 확인하기 (5) | 2020.08.31 |
파이썬 크롤링을 활용하여 캔버스 이미지 저장하기 (6) | 2020.08.29 |
댓글