스크래핑과 크롤링

이재홍·2022년 2월 2일
1
post-custom-banner

스크래핑(cheerio)

웹사이트에서 정보를 한번만 긁어 가져오는 것을 스크래핑이라합니다.
정보를 원하는 웹사이트에 접속해서 html파일을 받아오고 원하는 정보만 추려내는 작업을 cheerio를 통해 쉽게 할 수 있습니다.

import axios from 'axios';
import cheerio from 'cheerio';

async function getOpenGraph(mydata) {
  const myaddress = mydata.contents.split(' ').filter(el => el.includes('http'));
  const html = await axios.get(myaddress[0]);
  const $ = cheerio.load(html.data);
  $('meta').each((_, el) => {
    const key = $(el).attr('property')?.split(':')[1]; // ? 옵셔널 체이닝 앞에가 있으면 실행
    if (key) {
      const value = $(el).attr('content');
      console.log(key, value);
    }
  });
}

const mydata = {
  title: '안녕',
  contents: '여기는 https://naver.com 입니다!',
};

getOpenGraph(mydata);

네이버에서 받아온 html파일을 cheerio를 통해 meta태그를 찾고
meta태그에서 속성이 property인 경우에 값을 :기준으로 잘라 og:title이면
title을 가져오고 content 속성의 값도 가져와 정보를 저장할 수 있습니다.
이렇게 저장된 정보는 특히 채팅창등에서 해당 url의 미리보기 데이터로 활용됩니다.

크롤링(puppeteer)

한번이 아닌 지속적으로 정보를 긁어오고싶다면 puppeteer로 크롤링이 가능합니다.

import puppeteer from 'puppeteer';

async function startCrawling() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 720 });
  await page.goto('https://www.goodchoice.kr/product/search/2');
  await page.waitForTimeout(1000);

  const stage = await page.$eval(
    '#poduct_list_area > li:nth-child(2) > a > div > div.name > div > span',
    el => el.textContent
  );
  const location = await page.$eval(
    '#poduct_list_area > li:nth-child(2) > a > div > div.name > p:nth-child(4)',
    el => el.textContent
  );
  const price = await page.$eval(
    '#poduct_list_area > li:nth-child(2) > a > div > div.price > p > b',
    el => el.textContent
  );
  // #poduct_list_area > li:nth-child(3) > a > div > div.price > p > b
  console.log(stage);
  console.log(location.trim());
  console.log(price);

  await browser.close();
}

startCrawling();

puppeteer는 사이트자체를 복제하여 브라우저로 띄울수 있으며 내부 로그인등도 가능하게 해줍니다.

import puppeteer from 'puppeteer';
import mongoose from 'mongoose';
import { Stock } from './models/stock.model.js';
mongoose.connect('mongodb://localhost:27017/codecamp');

async function startCrawling() {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.setViewport({ width: 1280, height: 720 });
  await page.goto('https://finance.naver.com/item/sise.naver?code=005930');
  await page.waitForTimeout(1000);
  const myIframePage = await page
    .frames()
    .find(iframe => iframe.url().includes('/item/sise_day.naver?code=005930'));

  for (let i = 3; i <= 7; i++) {
    await page.waitForTimeout(3000); // 텀을 줘서 차단안당하게. (for문으로 반복하면 너무빠르게 요청되기에 공격차단)
    const mydate = await myIframePage.$eval(
      `body > table.type2 > tbody > tr:nth-child(${i}) > td:nth-child(1) > span`,
      el => el.textContent
    );
    const myprice = await myIframePage.$eval(
      `body > table.type2 > tbody > tr:nth-child(${i}) > td:nth-child(2) > span`,
      el => el.textContent
    );
    const mystock = new Stock({
      name: '삼성전자',
      date: mydate,
      price: Number(myprice.replace(',', '')),
    });
    await mystock.save();
    console.log(`날짜: ${mydate}, 가격: ${myprice}`);
  }

  await browser.close();
}

startCrawling();

사이트에서 iframe을 사용할경우 iframe의 정보를 불러오기 위해 추가적인 코드가 필요합니다.
원하는 데이터를 원하는 만큼 for문으로 가져와 DB에 저장할 수 있습니다.

post-custom-banner

0개의 댓글