본문 바로가기

Node.js/node crawling

노드 크롤링 - csv에 있는 주소를 통해 puppeteer 크롤링, csv파일 작성하기

csv 파일을 읽어서 각각 페이지들을 csv에 적혀있는 주소들에 접근해서

접근한 경우 page의 .score.score_left .star_score을 가져온다 .

만약에 scroeEl가 정상적로 받아와졌다면

태그의  값을 textContent로 가져온다

 

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

const csv = fs.readFileSync("./csv/data.csv");

//parse 메서드 -> 2차원배열화
const records = parse(csv.toString());
// console.log(records);

const crawler = async () => {
  const browser = await puppeteer.launch({ headless: false });
  try {
    await Promise.all(
      records.map(async (r, i) => {
        try {
          const page = await browser.newPage();
          // 페이지가 띄워졌을때
          await page.goto(r[1]);
          //접근
          const scoreEl = await page.$(".score.score_left .star_score");
          if (scoreEl) {
            //찾은 태그를 통해서
            //textContent를 가져오기
            const text = await page.evaluate((tag) => tag.textContent, scoreEl);
            console.log(r[0], '평점', text.trim());
          }
          //사람인척 하는 트릭 
          await page.waitFor(3000);
          await page.close();
        } catch (err) {
          console.log(err);
        }
      })
    );
  } catch (err) {
    console.log(err);
  } finally{
    
  await browser.close();
  }

};

crawler();

 

 

 

 

 

csv-stringify 모듈을 추가해준다

 

parse는 일반 문자열을 배열 형태로 변경해줬기때문에

stringify는 배열형태를 일반 문자열로 바꾸어서

파일시스템을 활용해서 작성할 수 있도록 해준다.

 

 

const parse = require("csv-parse/lib/sync");
const fs = require("fs");
const stringify = require('csv-stringify/lib/sync');
const puppeteer = require("puppeteer");
console.log(__dirname);
const csv = fs.readFileSync(__dirname+"/csv/data.csv");

//parse 메서드 -> 2차원배열화
const records = parse(csv.toString());
// console.log(records);

const crawler = async () => {
    const browser = await puppeteer.launch({ headless: false });
  try {
    const result = [];
    await Promise.all(
      records.map(async (r, i) => {
        try {
          
          const page = await browser.newPage();
          // 페이지가 띄워졌을때
          await page.goto(r[1]);
          //접근
          const scoreEl = await page.$(".score.score_left .star_score");
          if (scoreEl) {
            //찾은 태그를 통해서
            //textContent를 가져오기
            const text = await page.evaluate((tag) => tag.textContent, scoreEl);
            console.log(r[0], '평점', text.trim());
            result.push([r[0], r[1], text.trim()]);
          }
          //사람인척 하는 트릭 
          await page.waitFor(3000);
          await page.close();
          const str = stringify(result);
          fs.writeFileSync("csv/result.csv", str);
        } catch (err) {
          console.log(err);
        }
      })
    );
  } catch (err) {
    console.log(err);
  } finally{
    
  await browser.close();
  }

};

crawler();

 

 

 

이렇게 진행하면 원본의 순서와 달라지게 된다 

 

원본

 

result.push 부분을 

아래와같이 리팩토링을 진행하면 

 

 

 

const parse = require("csv-parse/lib/sync");
const fs = require("fs");
const stringify = require('csv-stringify/lib/sync');
const puppeteer = require("puppeteer");
console.log(__dirname);
const csv = fs.readFileSync(__dirname+"/csv/data.csv");

//parse 메서드 -> 2차원배열화
const records = parse(csv.toString());
// console.log(records);

const crawler = async () => {
  const browser = await puppeteer.launch({ headless: false });
  try {
    const result = [];
    await Promise.all(
      records.map(async (r, i) => {
        try {
          
          const page = await browser.newPage();
          // 페이지가 띄워졌을때
          await page.goto(r[1]);
          //접근
          const scoreEl = await page.$(".score.score_left .star_score");
          if (scoreEl) {
            //찾은 태그를 통해서
            //textContent를 가져오기
            const text = await page.evaluate((tag) => tag.textContent, scoreEl);
            console.log(r[0], '평점', text.trim());
            result[i] = [r[0], r[1], text.trim()] ;
          }
          //사람인척 하는 트릭 
          await page.waitFor(3000);
          await page.close();
          const str = stringify(result);
          fs.writeFileSync("csv/result.csv", str);
        } catch (err) {
          console.log(err);
        }
      })
    );
  } catch (err) {
    console.log(err);
  } finally{
    
  await browser.close();
  }

};

crawler();

 

이제 정상적으로 순서가 보장된 채로 출력이 된다.

 

 

 

 

Evaluate를 활용한 리팩토링 

evaluate안에서는 document.querySelector등 선택자가 사용이 가능하기때문에 

eavaluate 안에서 선택자를 통해 가져오는 방식으로 리팩토링이 가능하다

 

 

const parse = require("csv-parse/lib/sync");
const fs = require("fs");
const stringify = require('csv-stringify/lib/sync');
const puppeteer = require("puppeteer");
console.log(__dirname);
const csv = fs.readFileSync(__dirname+"/csv/data.csv");

//parse 메서드 -> 2차원배열화
const records = parse(csv.toString());
// console.log(records);

const crawler = async () => {
  const browser = await puppeteer.launch({ headless: false });
  try {
    const result = [];
    await Promise.all(
      records.map(async (r, i) => {
        try {
          
          const page = await browser.newPage();
          // 페이지가 띄워졌을때
          await page.goto(r[1]);
          //접근
        //  const 태그 핸들러 = await page.${선택자};
       const text =  await page.evaluate(() => {
          // 이안에서 document는 사용이 가능하다
          const score = document.querySelector(".score.score_left .star_score");
          if(score){
            return score.textContent;     
          }
        });
        if(text){
          console.log(r[0], '평점', text.trim());
          result[i] = [r[0], r[1], text.trim()];
        }
         
          //사람인척 하는 트릭 
          await page.waitFor(3000);
          await page.close();
          const str = stringify(result);
          fs.writeFileSync("csv/result.csv", str);
        } catch (err) {
          console.log(err);
        }
      })
    );
  } catch (err) {
    console.log(err);
  } finally{
    
  await browser.close();
  }

};

crawler();