NodeJS 웹 크롤링 Ch01

수박·2020년 9월 30일
0

nodejs

목록 보기
15/19

노드 웹크롤링


코드 예제

1.1 웹 크롤러소개

  • CRAWL : 기어다니다
  • 웹 사이트를 기어다니면서 정보를 수집하는 봇 = 크롤러
  • 크롤링한걸 영리적 목적으로 쓸 때 문제가 생길수도 있음.
  • 자스로 크롤링하면 생산성이 좋당


1.2 CSV - Parse 패키지로 csv 파싱하기

  • CSV? comma separated values
    • 콤마와 줄바꿈으로 구분된 값
  • npm i csv-parse : csv를 parse하는 모듈
//모듈을 사용하기 위한 부분
const parse = require('csv-parse/lib/sync');
//csv 파일을 읽어오기 위한 모듈
const fs = require('fs');
//csv는 버퍼형식임. csv파일을 읽어옴
const csv = fs.readFileSync('csv/data.csv');
//0,1로 이루어진 버퍼를 문자열로 변환해줌
//parse메서드가 문자열을 2차원 배열로 바꿔줌
const records = parse(csv.toString('utf-8'));
records.forEach((r, i) => {
  console.log(i, r);
});


1.3 xlsx 패키지로 엑셀 파싱하기

const xlsx = require('xlsx');


//readfile로 엑셀파일 읽기
const workbook = xlsx.readFile('xlsx/data.xlsx');
console.log(Object.keys(workbook.Sheets)); // TODO: workbook.SheetNames
const ws = workbook.Sheets.영화목록;
const records = xlsx.utils.sheet_to_json(ws); // TODO: 강좌에서 header 옵션 보여주기
//entries()로 사용하면 객체가 [인덱스, 값]형태 이터레이터로 변환됨.
for (const [i, r] of records.entries()) {
  console.log(i, r);
}


1.4 axios-cheerio로 첫 크롤링하기 (엑셀파일의 url로 요청 -> 파싱하여 엑셀에 write)

가장 간편하게 크롤링하는 방법

axios + cheerio 조합으로 가능

  • axios : ajax 라이브러리, 페이지를 요청하고 html을 응답받음
  • cheerio : html 파싱
  
const xlsx = require('xlsx');
const axios = require('axios');
const cheerio = require('cheerio');
const add_to_sheet = require('./add_to_sheet');

const workbook = xlsx.readFile('xlsx/data.xlsx');
const ws = workbook.Sheets.영화목록;//work sheet
const records = xlsx.utils.sheet_to_json(ws);

const crawler = async () => {
  add_to_sheet(ws, 'C1', 's', '평점');
  await Promise.all(records.map(async (r) => {
      //promise.all은 동시에 진행되지만 순서는 보장되지 않음.
      //링크에 get요청을 보낸다
    const response = await axios.get(r.링크);
      //요청이 성공했으면,
    if (response.status === 200) {
      const html = response.data;
        //html = html 문자열 cheerio로 로드-> 태그들에 접근 가능함
      const $ = cheerio.load(html);
        //css선택자로 원하는 태그를 선택할 수 있어야한다.
      const text = $('.score.score_left .star_score').text();
      console.log(r.제목, '평점', text.trim());
      const newCell = 'C' + (i + 2);
      add_to_sheet(ws, newCell, 'n', text.trim()); // 액셀에 쓰기 위한 파일호출 1.8장에 내용 있음
    }
  }));
  xlsx.writeFile(workbook, 'xlsx/result.xlsx'); // 엑셀에 새로 쓰기
};
crawler();


1.5 promise, all과 for of문의 차이

  • Promise.all은 동시에 진행되고 순서가 보장되지 않음

    • for of문은 순서를 보장해줌

      • promise.all은 한번에 여러 요청을 보낼 수 있어서 속도가 엄청 빠르나 for of는 하나를 보내고 응답을 받고나서야 다시 요청을 보내기 떄문에 순서가 보장되나 느림
      • 속도와 순서의 반비례관계 ->트레이드오프
    • 순서가 보장하려면 for of + await를 같이 쓰면 된다

    • const crawler = async() => {
      	for (const [i, r] of records.entries()){
            const response = await axios.get(r.링크);
            if (response.status === 200) {
                const html = response.data;
                  //html = html 문자열 cheerio로 로드-> 태그들에 접근 가능함
                const $ = cheerio.load(html);
                  //css선택자로 원하는 태그를 선택할 수 있어야한다.
                const text = $('.score.score_left .star_score').text();
                console.log(r.제목, '평점', text.trim());
          	}
          }
      }


1.6 xlsx 패키지

  • axios로 요청했을 때 HTML응답을 반환하지 않는 페이지도 있음.

    • puppeteer로는 가능함
    • 간단한 페이지는 axios cheerio
  • 크롤링된 데이터에 컬럼명의 속성을 가지게 할 수 있음

    • const records = xlsx.utill.sheet_to_json(ws, {header : 'A }); : header를 추가함.
    • { A : 타이타닉, B : 링크 } { A : 아바타, B : 링크} .. 이런식으로 표현 가능
  • 패키지사용 : ws['!ref']; -> 파싱할 데이터 구역을 반환함 (A1 : B11) A1부터 ~ B11까지 파싱할 범위를 지정함.

  • const workbook = xlsx.readFile('xlsx/data.xlsx'); -> workbook.SheetNames로 Sheet이름들을 반환받을 수 있음

    • Sheet 별 코딩 가능


1.7 api와의 차이점, 자동화

  • 크롤링 VS API?
    • API를 쓰는게 당연히 좋다
    • 그러나 API는 제공자가 주고싶은 정보만 줄 수 있는 것.
  • 크롤링 : 수강신청, 영화티켓, 자동로그인 등을 만들 수 있음.

1.8 엑셀에 쓰기

  • node에서 액셀에 글을 작성하려면 파일을 작성해야함.

  • const xlsx = require('xlsx');
    
    function range_add_cell(range, cell) {
      var rng = xlsx.utils.decode_range(range);
      var c = typeof cell === 'string' ? xlsx.utils.decode_cell(cell) : cell;
      if (rng.s.r > c.r) rng.s.r = c.r;
      if (rng.s.c > c.c) rng.s.c = c.c;
    
      if (rng.e.r < c.r) rng.e.r = c.r;
      if (rng.e.c < c.c) rng.e.c = c.c;
      return xlsx.utils.encode_range(rng);
    }
    
    module.exports = function add_to_sheet(sheet, cell, type, raw) {
      sheet['!ref'] = range_add_cell(sheet['!ref'], cell);
      sheet[cell] = { t: type, v: raw };
    };
  • add_to_sheet(ws, 'C1' , 's', '평점');

0개의 댓글