상세 컨텐츠

본문 제목

크롤링을 위한 puppeteer 기본 pt.2

CODING/etc.

by 뚜뚜 DDUDDU 2022. 5. 28. 01:55

본문

크롤링을 위해서주로 사용하는 puppeteer 기본크롬 창 띄우는 실습 예제

const cheerio = require('cheerio');
const axios = require('axios');
const xlsx = require('xlsx');
const add_to_sheet = require('./add_to_sheet'); // 엑셀에 크롤링 한 내용 추가시
const puppeteer = require('puppeteer');
const { stringify } = require('csv-stringify');
const { parse } = require('csv-parse');
const fs = require('fs');
const workbook = xlsx.readFile('xlsx/data.xlsx');
const ws = workbook.Sheets.영화목록; // ws: 워크시트

/////////////// 엑셀관련 ////////////////
// header: A - 엑셀파일에서 1행엔 속성값 들어가는데(r.제목), 대신 r.A이렇게 설정
// const records = xlsx.utils.sheet_to_json(ws);
// // const records = xlsx.utils.sheet_to_json(ws, { header: 'A' });
// console.log(records);
// console.log(ws['!ref']); // 범위값 출력(a1:b11 -> A2:B11)

// console.log(workbook.SheetNames) // 여러시트 배열로
// for (const name of workbook.SheetNames){
//   const ws = workbook.Sheets[name];
//   //여러 시트일 때
// }
// records.shift(); // 첫행 제외하고 출력


////////////// csv 관련 ///////////////
//readFileSync: 파일 읽어들이는 메서드
const csv = fs.readFileSync('csv/data.csv');
// 1. 문자열이 버퍼이기에 문자열로 바꿔줘야 함
// 2. parse() ==> 2차원 배열로 변경
const records = parse(csv.toString('utf-8'));

//////////////// 단순출력 /////////////////
// for (const [i, r] of records.entries()) {
//   console.log(i, r.제목, r.링크);
// }

// records.forEach((r, i) => {
//   console.log(i, r);
// });


/////////////// 엑셀 파싱 및 크롤링 - cheerio //////////
// const crawler = async () => {
//   // 엑셀파일에 열 추가
//   add_to_sheet(ws, 'C1', 's', '평점');

//   for (const [i, r] of records.entries()) {
//     const response = await axios.get(r.링크);
//     // const response = await axios.get("https://movie.naver.com/movie/bi/mi/basic.naver?code=196047#");
//     if (response.status === 200) { // 응답이 성공한 경우
//       const html = response.data;
//       // console.log(html);
//       const $ = cheerio.load(html);
//       const text = $('.score.score_left .star_score').text();
//       console.log(r.제목, '평점', text.trim());
//       const newCell = 'C' + (i + 2); // 2부터 11까지 필요
//       add_to_sheet(ws, newCell, 'n', parseFloat(text.trim()));
//     }
//   }
//   xlsx.writeFile(workbook, 'xlsx/result.xlsx'); // 열 추가해서 새로 만든다.
//   // // Promise.all은 순서가 보장되지 않음, 동시에 시행되긴 함 - 속도는 빠름
//   // await Promise.all(records.map(async (r) => {

//   // }));
// };


////////////// pupeeteer ////////////////
const crawler = async () => {
  try {
    const result = [];
    // 실무에서는 개발할때만 화면 띄우고 배포할때 화면 안띄움
    // headless: true 하면 브라우저 보이지 않음
    // 더 실무적으로: headless: process.env.NODE_ENV === 'production'
    const browser = await puppeteer.launch({ headless: false });
    // const browser = await puppeteer.launch();
    const page = await browser.newPage();
    await page.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.64 Safari/537.36')

    await Promise.all(records.map(async (r, i) => {
      try {
        result[i] = r;
        await page.goto(r[1]);
        console.log(await page.evaluate('navigator.userAgent'))
        // const 태그핸들러 = await page.$(선택자);
        // const scoreEl = await page.$('.score.score_left .star_score'); // TODO: 바로 evaluate 하는 방식도 알려주기
        // dom 함수쓰려면 evaluate 내에서 써야 함
        const text = await page.evaluate(() => {
          const score = document.querySelector('.score.score_left .star_score');
          if (score) {
            return score.textContent;
          }
        });
        if (text) {
          console.log(r[0], '평점', text.trim());
          result[i][2] = text.trim();
        }

        await page.waitFor(3000);
        await page.close();
      } catch (e) {
        console.error(e);
      }
    }));

    await browser.close();
    const str = stringify(result);
    fs.writeFileSync('csv/result2.csv', str);
  } catch (e) {
    console.error(e);
  }
};

crawler();

관련글 더보기

댓글 영역