안수찬의 개발이야기

Node.js 를 이용한 웹 데이터 수집하기

Introduction

안수찬 @dobestan

안수찬 @dobestan

소프트웨어 생태계에 기여할 수 있는 실용주의 프로그래머가 되고자 합니다. 나는 안수찬이다. 그러므로 나는 할 수 있다.


nodejs

Node.js 를 이용한 웹 데이터 수집하기

Posted by 안수찬 @dobestan on .
Featured

nodejs

Node.js 를 이용한 웹 데이터 수집하기

Posted by 안수찬 @dobestan on .

최근에 패스트캠퍼스에서 Node.js 로 시작하는 웹 프로그래밍 강의를 진행하고 있습니다. 수업에서는 Express 기반의 백엔드 어플리케이션을 만드는 내용을 다루고 있습니다. 개인 프로젝트를 진행하시며 이와 관련된 질문을 많이 해서 간단하게 블로그 글로 정리해보았습니다.

이 글에서는 크롤링할 사이트로 제 블로그 의 메인 페이지에서, 포스트 제목을 크롤링하고자 합니다.

블로그 메인 페이지

페이지당 7개의 포스트가 있고, 각각의 포스트는 "제목", "일부 본문", "작성일자", "작성자", "태그" 들의 정보가 있습니다.

데이터 수집하기 - Crawling, Scraping, Parsing

웹 사이트의 데이터를 수집하는데 있어서 크게 2가지만 정확하게 기억하시면 됩니다. 일반적으로는 이 일련의 과정을 크롤링(Crawling) 이라고 부르기는 하지만, 각각의 용어에 차이점이 있습니다.

  1. Scraping - 데이터를 어떻게 잘 가져올 것인가?
    • Authentication - 만약, 인증된 사용자만 정보를 볼 수 있다면 어떻게 정보를 가져올 수 있을까?
    • Pagination - 만약, 여러 페이지에 걸쳐서 데이터가 나눠져있다면 어떻게 이를 쉽게 가져올 수 있을 것인가?
  2. Parsing - 데이터를 어떻게 잘 추출할 것인가?

"Crawling", "Parsing", "Scraping" 의 용어에 대해서는 Quora > "What is the difference between crawling, parsing and scraping?" 에 자세히 설명되어 있으니, 한번 살펴보시면 좋을 것 같습니다.

그래서 우리가 어떤 프로그래밍 언어를 사용하던 간에 각각의 역할(Crawling, Scraping, Parsing)에 적합한 모듈/패키지를 활용하면 이러한 작업들을 훨씬 편하게 작업들을 처리할 수 있습니다. Node.js 에서도 각각의 작업을 수행하기 위한 다음과 같은 선택지 들이 있습니다.

  1. Scraping - http, https, request
  2. Parsing - JSDOM, cheerio

이 포스트에서는 HTML 데이터를 가져오기 위해서는 request 를, 크롤링한 HTML 데이터를 파싱하기 위해서는 cheerio 를 사용해서 진행하도록 하겠습니다.

$ npm install request
$ npm install cheerio

Scraping

이 예제는 사실상 하나의 페이지에서 데이터를 가져오는거라 Scraping 이라고 부르기에도 민망합니다 이 부분은 공식 문서에 설명이 굉장히 잘 되어 있는 편이므로 가능하면 request 를 한번 살펴보시면 좋을 것 같습니다.

var request = require("request");  
var url = "https://dobest.io/";

request(url, function(error, response, body) {  
  if (error) throw error;
    console.log(body);
  });
});

Parsing

우리가 HTTP Request 를 통해서 받아온 HTML 데이터에서 원하는 데이터를 추출하기 위해서, 가장 먼저 해야하는 일은 "HTML 구조를 살펴보는 일" 입니다. 즉, 우리가 원하는 데이터가 어디 있는지 정확하게 파악하는 것이 중요합니다.

HTML 구조를 살펴보세요

구글 크롬의 개발자 도구를 이용해서 HTML 구조가 어떤 식으로 되어 있는지 살펴보세요. 개발자 도구 좌측 상단의 "Element Inspector" 를 이용하면 조금 더 쉽게 찾으실 수 있습니다.

...
<section class="posts postindex wrapper">  
    <article class="post">
      <h1>제목</h1>
    <article>
    <article class="post">...<article>
    <article class="post">...<article>
</section>  
...

이렇게 HTML 구조를 살펴보니 몇 가지 공통점이 보입니다. ( 이 블로그의 경우에는 굉장히 간결하고 직관적으로 HTML 구조가 만들어져 있습니다. )

  • posts 라는 class 를 가진 section element ( section.posts )
    • post 라는 class 를 가진 article element ( article.post )

가 있는 형태로 되어 있습니다. 우리가 이를 CSS Selector 방식으로 작성해보면 다음과 같이 작성할 수 있습니다: section.posts article.post

우리가 HTML Parser 로 사용하려고 하는 cheerio 는 웹 클라이언트 자바스크립트 라이브러리인 jQuery 스타일로 element 를 선택할 수 있어, 기존의 Selector 방식을 그대로 이용할 수 있습니다.

var request = require("request");  
var cheerio = require("cheerio");  
var url = "https://dobest.io/";

request(url, function(error, response, body) {  
  if (error) throw error;

  var $ = cheerio.load(body);

  var postElements = $("section.posts article.post");
  postElements.each(function() {
    var postTitle = $(this).find("h1").text();
    var postUrl = $(this).find("h1 a").attr("href");
  });
});

따라서, 우리가 작성한 코드를 실행해보면 다음과 같이 정상적으로 결과가 나오는 것을 확인해볼 수 있습니다.

크롤링 결과

정상적으로 블로그 메인 페이지에 있던 7개의 포스트 정보가 크롤링되는 것을 확인할 수 있다.

안수찬 @dobestan

안수찬 @dobestan

https://dobest.io/

소프트웨어 생태계에 기여할 수 있는 실용주의 프로그래머가 되고자 합니다. 나는 안수찬이다. 그러므로 나는 할 수 있다.

View Comments...