[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
개발기록

2개의 댓글

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.

답글 달기
comment-user-thumbnail
2024년 11월 1일

JSON is a lightweight data format for storing and transmitting data. It is mainly used for exchanging data between clients and servers in web applications. JSON is easy to read and write and represents data in a format that is easy for humans to understand. https://xzroms.com/switch-roms/

답글 달기