[nodejs 크롤링] 1장. 웹크롤러 파싱

Joey Hong·2020년 9월 17일
1

크롤링

목록 보기
1/5

제로초 github

1-1. 웹 크롤러 소개

🤖 크롤링이란?

봇을 만들어 웹사이트의 정보를 수집하는 것

  • 크롤링 데이타를 영리적 목적으로 사용시 문제가 될 수 있다
  • 허락을 맡거나 제공된 API를 사용하는 것을 권장

🤖 크롤링 언어: node.js(javascript)

  • c, c++이 속도가 더 빠르지만
  • node.js가 생산성이 좋다
    • 웹을 구성하는 언어 javascript를 사용
    • 언어간 전환 비용↓, 호환성↑

1-2. csv-parse 패키지로 csv 파싱하기

🤖 node 폴더 만들기

npm init
  • start를 node index로 바꿔준다
  {
      "main": "index.js",		//프로젝트의 메인 파일 명시
      "scripts": {
          "start": "node index"
      },
  }

🤖 CSV(Coma Separated Value)

컴마랑 줄바꿈으로 구분된 값들로 실제 엑셀에서 불러들일 수 있는 파일 형식

//data.csv
타이타닉, https://movie.naver.com/movie/bi/mi/basic.nhn?code=18847
아바타, https://movie.naver.com/movie/bi/mi/basic.nhn?code=62266
.
.

🥊 CSV parser

파싱이란 자바스크립트가 아닌 데이타를 자바스크립트로 변환하는 것

  npm i csv-parse

🥊 parser 함수 사용

☸ 바퀴를 재발명하지마라
이미 있는 parser함수 사용

  //index.js
  const parse = require('csv-parse/lib/sync');	//csv parser 함수
  const fs = require('fs');		//file sync module

  const csv = fs.readFileSync('csv/data.csv');	//fs의 버퍼로 파일을 읽는 메소드
  const records = parse(csv.toString('utf-8'));	//버퍼를 문자열로 전환 후 2차원 배열로 parse
  • require('node_modules/csv-parse/lib/sync.js')
    • parser 함수가 들어있는 sync.js 파일
  • fs
    • csv 파일을 읽기 위한 모듈
  • readFileSync
    • 파일을 읽어들이는 메소드
    • 0, 1로 이루어진 버퍼형식으로 data.csv를 읽는다
  • npm start로 실행

🤖 puppeteer 배포

  • node로 배포하는 것이 좋다
    • puppetter가 javascript로 되어있기때문
    • node로 설치하는 패키지라서
  • 배포방식
    • 노드 서버로
    • 혹은 일렉트론같은 테스크탑 프로그램으로

1-3. xlsx 패키지로 엑셀 파싱하기

🤖 puppeteer 램

  • 프로그래밍으로 조작할 수 있는 크롬 브라우저
    • 크롬 브라우저는 램 필요
  • 구글은 1GB 램버서 추천
    • 비용이 든다

🤖 xlsx 파서 함수

  • xlsx 엑셀 파일로 주어진 파일 파싱하기
    • ∵ 기획자가 csv 파일 형식을 모를 가능성↑
  • 만드는 것이 너무 복잡하고 거의 불가능하니 패키지 사용
    • A1, A2 등 각 칸에 관한 정보
    • 폰트, 배경, 색상 등에 관한 정보
npm i xlsx
//index.js
const xlsx = require('xlsx');	//엑셀 파서

const workbook = xlsx.readFile('xlsx/data.xlsx'); //파싱

const ws = workbook.Sheets.영화목록;	//엑셀의 '영화목록' 시트 접근

const records = xlsx.utils.sheet_to_json(ws);	//row들을 JS 객체형식으로
  • sheet_to_json
    • 파싱한 엑셀 자료를 자바스크립트 객체로 전환하는 함수
    • 공식문서 참조
  • 엑셀자료가 records에 JS형식으로 담겼다
  • 이 데이타를 다시 csv, 엑셀, database 모두에 넣을 수 있다

🤖 비동기

  • Javascript는 single thread라 비동기일 수밖에 없다.
  • forEach와 for문을 이해하고 비동기를 자유자재로 다룰 수 있어야한다.

🥊 병렬처리 vs 순차처리

병렬처리 (in prarallel)
  • forEach는 배열을 돌며 callback을 호출만 하고 종료된다
    • 비동기 작업 후 어떤 작업을 해야한다면 (끝나는 타이밍 감지 필요) forEach가 아닌 map과 Promise.all을 사용하는 것이 좋다
  • 한꺼번에 여러 비동기 작업을 수행
    • 파일을 읽어온 후 어떤 작업을 하는 경우 순서 상관없이 읽어오기만 하려면 병렬처리가 성능적으로 우수하다
순차처리 (in sequence)
  • for 또는 for...of문을 통해 순차처리가 가능하다
    • 배열의 요소들에 대해 차례대로 비동기 작업을 수행하는 것
    • 실행 순서가 보장되어야할 때 사용

1-4. axios-cheerio로 크롤링

  • 간단한 크롤링밖에 안된다
    • axios로 get할 때 html이 비어서 오는 경우가 있다
//index.js
//const xlsx = require('xlsx');
//const workbook = xlsx.readFile('xlsx/data.xlsx');
//const ws = workbook.Sheets.영화목록;
//const records = xlsx.utils.sheet_to_json(ws);

const axios = require('axios');		//html로 웹자료를 get
const cheerio = require('cheerio');		//html을 JS로 변환

const crawler = async () => {
	await Promise.all(records.map(async (r) => {
    	const response = await axios.get(r.링크);
        if (response.status === 200)
        	const html = response.data;
            const $ = cheerio.load(html);
            const text = $('.score.score_left .star_score').text();	//원하는 html 태그 지정 (jquery API 사용)
      		console.log(r.제목, '평점', text.trim());	//trim()으로 공백 제거
        }
    
};
crawler();
  • cheerio는 jquery API 사용 가능
    • 원래 JS DOM API라면 text()가 아닌 textContent()를 써야한다
    • html()로 태그를 가져올 수 있고 text()로 내부 텍스트만 가져올 수 있다

1-5. Promise.all과 for of문의 차이

🤖 순차처리로 변환

//index.js
const crawler = async () => {
	for (const [i, r] of records.entries()) {
    	const response = await axios.get(r.링크);
        if (response.status === 200)
        	const html = response.data;
            const $ = cheerio.load(html);
            const text = $('.score.score_left .star_score').text();
      		console.log(r.제목, '평점', text.trim());
        }  
};

1-6. 보너스 xlsx 패키지

🤖 엑셀파싱 추가 기능

🥊 객체 이름을 따로 지정해서 저장

//엑셀 맨 위 제목행만 제거
//index.js
const records = xlsx.utils.sheet_to_json(ws, { header: 'A' });
records.shift();	//파싱된 제목 제거
  • column명 A, B, C 등이 객체 이름이 된다
  • 엑셀시트의 제목까지 자료로 저장되니 shift()로 제거

🥊 '!ref'로 파싱할 범위 지정

엑셀 시트의 A1부터 B11까지 파싱이 목표

//index.js
//방법1
ws['!ref'] - ws['!ref'].split(':').map((v, i) => {
  if (i === 0) {
  	return 'A2';
  }
  return v;
}).join(':'); 	
const records = xlsx.utils.sheet_to_json(ws, { header: 'A' });


//방법2
ws['!ref'] = 'A2:B11';
const records = xlsx.utils.sheet_to_json(ws, { header: 'A' });

🥊 특정 시트 자료 가져오기

//index.js
//원하는 시트의 자료 접근
const ws = workbook.SheetNames.영화제목;


//시트별로 따로 코딩 시
for ( const name of workbook.SheetNames) {
	const ws = workbook.Sheets[name];
}

1-7. 보너스 api와의 차이점, 자동화

🤖 API 사용

🥊 장점

  • 정보가 정확
  • 법적 문제X

🥊 단점

  • 사이트에서 제공하는 정보만 취득 가능

🤖 크롤링

  • 리액트, 앵귤러, 뷰 등처럼 URL이 바뀌지 않은 페이지의 자료를 가져올 수 있다
    • 접근가능한 것은 크롤링 가능

1-8. 보너스 - 엑셀에 쓰기

엑셀파일에 도로 입력하기

🤖 add_to_sheet

//add_to_sheet.js
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);
}

//함수에 넣을 변수들: sheet, cell, type, raw
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함수의 변수
    • sheet - 값을 입력할 시트
    • cell - 값을 입력할 셀
    • type - 셀의 타입(일반, 숫자, 통화, 시간 등)
    • raw - 넣어줄 값

🤖 add_to_sheet함수 사용하기

  • add_to_sheet로 ws객체에 자료 추가
    • 별점 자료 추가하기
  • xlsx.writeFile로 엑셀에 자료 입력
    • 새로운 엑셀 파일로 리턴
//index.js
const add_to_sheet = require('./add_to_sheet');

const crawler = async () => {
	//객체에 새로운 열 추가
  	add_to_sheet(ws, 'C1', 's', '평점');		
  
	for (const [i, r] of records.entries()) {
    	const response = await axios.get(r.링크);
        if (response.status === 200)
        	const html = response.data;
            const $ = cheerio.load(html);
            const text = $('.score.score_left .star_score').text();		
      		console.log(r.제목, '평점', text.trim());      		
      
      		//C:2부터의 column으로 지정 (자료를 입력할 column구간)
      		const newCell = 'C' + (i + 2);	
      
      		//객체의 새 열에 자료 추가
      		add_to_sheet(ws, newCell, 'n', parseFloat(text.trim()));	
        }
  	//새로운 엑셀 시트에 write
	xlsx.writeFile(workbook, 'xlsx/result.xlsx');	
};

profile
개발기록

1개의 댓글

comment-user-thumbnail
2023년 11월 4일

Ryujinx, https://ryujinxfirmware.com/ in particular, distinguishes itself with its impressive array of features, making it a top pick for Nintendo Switch emulation. you'll have access to free Switch ROMs https://krnl.vip/nintendo-switch-roms/ without any hindrance. We offer direct download links that are free from intrusive ads.

답글 달기