Node.js로 velog 크롤링하기?

송철진·2023년 5월 26일
0

Toy Project

목록 보기
9/10

학습

Node.js로 inflearn 크롤링하기

  • 검색어가 한글일 경우 keyword를 그대로 입력하면 에러가 발생한다. 이러한 에러를 회피하기 위해 특수문자 등을 인코딩된 문자열로 치환하는 encodeURI()를 사용한다.

    encodeURI() - mdn
    이스케이프 제외: A–Z a–z 0–9 - _ . ! ~ * ' ( ) ; / ? : @ & = + $ , #

  • util.inspect(object, [options]): [object object]로 표현되는 객체에 대하여 그 구조를 점검하고 string타입으로 표현 및 반환한다. fs.writeFile(파일명, 데이터, 콜백함수)에서 데이터를 string으로 받기위해 사용했다.

  • $().each(): jquery에 선택자를 넘기면 그 선택자를 for문(반복문)과 같이 사용한다.
    참고 - https://webclub.tistory.com/455

  1. 일정하게 반복되는 div에 대하여
    상위 클래스 course_card_item을 아래와 같이 지정하고
 const $courseList = $(".course_card_item");

  1. course_title과 같은 하위 클래스는
<div class="course_title">한 입 크기로 잘라먹는 타입스크립트</div>

제이쿼리로 반복문을 돌려 구할 수 있다.

 $courseList.each((idx, node) => {
   	const title = $(node).find(".course_title").text();
   	console.log(title);
 }

소스 코드

typescript를 검색했을 때 강의 목록을 크롤링하여
id, 강의 제목, 강사, 가격(할인가 또는 없으면 현재가), 별점, 이미지url 정보를 log.txt파일에 입력받도록 구현했다.

const fs = require("fs");
const axios = require("axios"); // 외부API로 html구조를 가져옴
const cheerio = require("cheerio"); // 가져온 html 구조를 쉽게 parsing하게 해줌
const util = require("util");

const getHTML = async (keyword) => {
  try {
    return await axios.get(
      "https://www.inflearn.com/courses?s=" + encodeURI(keyword)
    );
  } catch (err) {
    console.log(err);
  }
};
const parsing = async (keyword) => {
  const html = await getHTML(keyword);
  const $ = cheerio.load(html.data); // jquery
  const $courseList = $(".course_card_item");

  let courses = [];
  $courseList.each((idx, node) => {
    courses.push({
      id: idx,
      title: $(node).find(".course_title:eq(0)").text(), // 2개의 노드를 가져오는데 첫번째 것만
      instructor: $(node).find(".instructor").text(),
      price:
        $(node).find(".price > .pay_price").text() ||
        $(node).find(".price").text(),
      rating: $(node).find(".star_solid").css("width"),
      img: $(node).find(".card-image > figure > img").attr("src"),
    });
  });

  const htmlString = util.inspect(courses, {
    showHidden: true,
    depth: null,
    colors: false,
  });
  fs.writeFile("log.txt", htmlString, (error) => {
    if (error) {
      console.error(error);
    } else {
      console.log("성공적으로 log.txt에 저장되었습니다.");
    }
  });
};

parsing("typescript");

결과

log.txt

[
  {
    id: 0,
    title: '한 입 크기로 잘라먹는 타입스크립트',
    instructor: '이정환 Winterlood',
    price: '₩38,500',
    rating: '100%',
    img: 'https://cdn.inflearn.com/public/courses/330452/cover/7f862bab-8519-4b31-afc6-26cb355833eb/330452-eng.png'
  },
  {
    id: 1,
    title: '타입스크립트 입문 - 기초부터 실전까지',
    instructor: '장기효(캡틴판교)',
    price: '₩41,250',
    rating: '98.9413988657845%',
    img: 'https://cdn.inflearn.com/public/courses/326082/cover/c6519e92-f334-46ac-8a31-6290db19b32a'
  },
  (...생략...)
  {
    id: 23,
    title: '만들면서 배우는 프론트엔드 DO IT 코딩 (Next.js, Typescript)',
    instructor: 'totuworld',
    price: '₩99,000',
    rating: '89.41176470588235%',
    img: 'https://cdn.inflearn.com/public/courses/329080/cover/c7af9560-eced-48dd-af9e-66b2e8ee17bc/329080-eng.jpg'
  },
  [length]: 24
]

velog 크롤링하기?

이제 내 velog의 시리즈 제목을 크롤링 해보자.

  • velog userId는 영소문자,숫자,밑줄만 사용되므로 encodeURI()가 불필요하다
const fs = require("fs");
const axios = require("axios");
const cheerio = require("cheerio");
const util = require("util");

const getHTML = async (keyword) => {
  try {
    return await axios.get(
      `https://velog.io/@${keyword}/series`
    );
  } catch (err) {
    console.log(err);
  }
};
const parsing = async (keyword) => {
  const html = await getHTML(keyword);
  const $ = cheerio.load(html.data);
  console.log(html.data);
  
  const $seriesList = $(".hpEiVB");

  let series = [];
  $seriesList.each((idx, node) => {
    series.push({
      id: idx,
      title: $(node).find("h4 > .hiUmEs").text(),
    });
  });
};

parsing("scroll0908");

그런데 안된다?! 브라우저에서 확인한 각 시리즈 div의 클래스명은 .sc-kYHfwS hpEiVB인데 아무것도 읽어오지 못한다 왜일까?

  1. html.data를 여러번 콘솔로 찍어본 결과, 클래스 명이 랜덤으로 계속 변하는 것이 확인됐다. 클래스명을 기준으로 크롤링하려고 했는데 클래스명이 동적이라니..

  2. cheerioLoaded를 비교 시:

  • 인프런은 해당 클래스명이 일치하는 24개의 강의 데이터를 확인할 수 있다.
  • 벨로그는 해당 클래스명이 일치하는 0개의 시리즈 데이터가 확인된다.

마무리

토이프로젝트는 기술적 한계로 중단됐지만
cheerio와 axios로 간단한 크롤링 방법을 익힐 수 있었다.


참조

  • 개발자의품격 - Node.js 크롤링 - 인프런 사이트 크롤링하기
    https://youtu.be/xbehh8lWy_A
profile
검색하고 기록하며 학습하는 백엔드 개발자

0개의 댓글