본문 바로가기

BackEnd/Node.js

Parse & Crawling To Node.js (노드로 파싱 및 크롤링하기)

파싱과 크롤링 전에 알아야 할 지식들을 순서대로 알아보자.

1. fs module

node.js 자체 모듈이다. 파일 io를 위해서 사용되고 있다.

 

사용법

fs.readFile(filename, [options], callback)

외부의 파일을 읽을 때 사용된다. 

이 때, callback 함수를 사용 할 경우 해당 메소드는 비동기적으로 작용하여 callback을 완료시킨다.

이 외에는 동기적으로 작동한다.

 

이 때 읽어들인 파일은 버퍼형태로 리턴되기 때문에 toString으로 인코딩 해주어야 한다.

const parser = require("csv-parse/lib/sync");
const fs = require("fs");

const csv = fs.readFileSync("csv/data.csv");
console.log(csv.toString("utf-8"));

< 결과가 문자열로 출력 된다>

해당 문자열을 배열이나 객체 형식으로 바꿀 수도 있겠지만, 그것보단 parse를 이용하면 쉽게 문제를 해결 할 수 있다.

2. parser

parse들은 파일 형식에 따라 종류들이 많다. 이번에는 그 중 테이블을 제공하는 엑셀 파일(csv, xlsx) 정도만 정리한다.

1) csv - parse

const parser = require("csv-parse/lib/sync");

모듈명은 csv-parse 이다.

파싱을 위해서 사용하는 것은 대신 sync파일의 메소드 이다.

해당 메소드는 csv파일을 배열에 데이터를 담은 배열로 전환한다.

const parser = require("csv-parse/lib/sync");
const fs = require("fs");

const csv = fs.readFileSync("csv/profile.csv");
const data = parser(csv.toString("utf-8"));
console.log(data); 

< 배열에 데이터가 담겼다 >

2) xlsx

csv 파일은 애초에 데이터베이스를 목적으로 만들어졌기 때문에, 데이터를 제외한 어떤 다른 데이터도 존재하지 않는다.

하지만 xlsx는 데이터의 각종 서식등 많은 meta 데이터가 존재 하기 때문에, fs를 이용하는 방법으로는 처리가 쉽지 않다.

const xlsx = require("xlsx");
const meta = xlsx.readFile("xlsx/profile.xlsx");
console.log(meta);

모듈은 xlsx이고 xlsx객체의 readFile 메소드로 파일을 읽어드리면 다음과 같은 결과가 나타난다.

< 아래로 내려가면 data도 존재 >

이 때 우리가 찾고자 하는 데이터는 Sheets.시트명에 존재한다.

const xlsx = require("xlsx");
const meta = xlsx.readFile("xlsx/profile.xlsx");
const data = meta.Sheets.프로필;
console.log(data);

< 결과 >

이제 이 데이터를 json객체로 변환할 수 있게 되었다.

xlsx.utils.sheet_to_json() 메소드를 이용하자.

const xlsx = require("xlsx");
const meta = xlsx.readFile("xlsx/profile.xlsx");
const data = meta.Sheets.프로필;
console.log(data);
const jsonData = xlsx.utils.sheet_to_json(data);
console.log(jsonData);

< 결과 >

3. Crawler

크롤링은 특정 페이지에 html 요청을 한 후에 필요한 데이터만 가공하는 것이다.

 

페이지를 요청하기 위해 axios를 이용하였다.

const crawler = async () => {
  const response = await axios.request({
    method: "GET",
    url:
      "http://www.weather.go.kr/weather/climate/past_table.jsp?stn=108&yy=2018&obs=07&x=16&y=6",
    responseType: "arraybuffer",
    responseEncoding: "binary"
  });

이번 포스팅에서는 기상청의 과거자료 데이터를 요청해보았는데, request시에 euc-kr 인코딩 관련 페이지들은 인코딩 문제가 발생한다.

이를 해결하기 위해서는 버퍼형식으로 요청을 한 후에 디코딩하는 형식으로 데이터를 가져와야한다.

 

버퍼한 값을 디코딩 하기 위해서는 npm 모듈인 iconv를 이용한다.

const axios = require("axios");
const iconv = require("iconv-lite");
const crawler = async () => {
  const response = await axios.request({
    method: "GET",
    url:
      "http://www.weather.go.kr/weather/climate/past_table.jsp?stn=108&yy=2018&obs=07&x=16&y=6",
    responseType: "arraybuffer",
    responseEncoding: "binary"
  });
  if (response.status == 200) {
    const html = iconv.decode(response.data, "euc-kr").toString();

해당 데이터의 body를 문자열로 받아 올 것이다.

다만 모든 body가 아닌 데이터들만 받아 와야 하는 상황인데, 정규표현식을 통해서도 가능하지만, 이를 해결해주는 모듈도 있다.

npm 모듈인 cheerio를 이용하자.

const crawler = async () => {
  const response = await axios.request({
    method: "GET",
    url:
      "http://www.weather.go.kr/weather/climate/past_table.jsp?stn=108&yy=2018&obs=07&x=16&y=6",
    responseType: "arraybuffer",
    responseEncoding: "binary"
  });
  if (response.status == 200) {
    const html = iconv.decode(response.data, "euc-kr").toString();
    const $ = cheerio.load(html);
    const text = $(".table_develop ")
      .text()
      .trim();
      

대체로 태그 앞뒤로 여백이 생기는데 trim()통해 어느 정도는 제거 해줄 수 있다.

하지만 모두 제거되는 것은 아니므로 나머지는 페이지의 구조를 보고 개인이 로직을 짜야한다.

< 결과 >

파싱하기 좋게 문자열이 줄력 됨을 확인 할 수 있다.

'BackEnd > Node.js' 카테고리의 다른 글

Microsoft / Typescript Express 보일러 플레이트 적용기  (0) 2019.08.28
Puppeteer.js 를 이용한 웹 자동화  (1) 2019.07.09
[MongoDB] 사용법  (0) 2019.01.26
[Express] 동영상 페이지 제작  (0) 2019.01.25
[Express]Pug mixins  (0) 2019.01.25