Cheerio로 스크레이퍼를 만드는 방법

이 게시물에서는 cheerio 을 사용하여 웹사이트를 스크랩하는 방법을 배운 다음 나중에 node.js 과 함께 사용할 수 있는 frontend 으로 스크랩한 데이터로 API를 생성합니다.

이 예에서 사용할 웹사이트는 pricecharting입니다.

You can contact me by telegram if you need to hire a Full Stack developer.

discord Appu#9136으로 저에게 연락할 수도 있습니다.

You can clone the repo if you want.

이 예제는 학습 목적으로만 사용됩니다.

프로젝트 생성


  • 터미널을 열고 다음을 입력하십시오.
  • mkdir 노드-cheerio-tut
  • cd node-cheerio-tut
  • npm 초기화 --y
  • 코드 .

  • 종속성


  • 신나게
  • 익스프레스
  • 노드몬

  • 종속성을 설치하려면 프로젝트 폴더로 이동하여 터미널을 열고 다음을 입력하십시오.

    npm i axios cheerio express mongoose
    


    그리고 dev 종속성 유형의 경우

    npm i -D nodemon
    


    프로젝트 파일 구조:



    node-cheerio-tut/
    ├── node_modules/
    ├── 공개/
    ├── 소스/
    │ ├── 노선/
    │ ├── 데이터베이스.js
    │ └── index.js
    └── 패키지.json

    목차


  • Setup the project
  • Using Cheerio to scrape data
  • Sending the response
  • Organizing our code
  • Conclusion


  • 먼저 package.json으로 이동하여 다음 행을 추가하십시오.

      "scripts": {
        "start": "node ./src index.js",
        "dev": "nodemon ./src index.js"
      },
    


    코딩하자

    1. 프로젝트 설정

    lets go to index.js inside the src folder and set up our basic server with express.

    const expres = require('express')
    
    const app = express()
    
    //server
    app.listen(3000, () => {
      console.log('listening on port 3000')
    })
    

    now let's run this command npm run dev and we should get this message:

    listening on port 3000
    

    Now in our index.js lets import axios and cheerio, then i''ll explain the code below.

    1. we're going to add a const url with the url value, in this case https://www.pricecharting.com/search-products?q= . (when you do a search in this web, you will be redirected to a new page, with a new route and a parameter with the value of the name you searched for.)




    따라서 우리는 해당 URL을 사용할 것입니다. 또한 웹사이트에는 두 가지 유형의 검색이 있습니다. 하나는 가격 기준이고 다른 하나는 시장 기준입니다. URL에 유형을 지정하지 않으면 기본적으로 시장 유형이 설정됩니다. 시장에서 게임 커버와 시스템을 반환하기 때문에 이렇게 둡니다(나중에 사용하겠습니다).
  • 우리는 post 요청을 할 때 app.use(express.json())을 얻고 싶지 않기 때문에 이 미들웨어 undefined을 추가할 것입니다.
  • 우리는 서버에 본문을 보내기 위해 post 메소드로 경로를 생성할 것입니다.
    test.http
    POST http://localhost:3000
    Content-Type: application/json
    
    {
      "game": "final fantasy"
    }
    



    final fantasy
    


    보시다시피 우리는 응답을 받고 있습니다. 이 경우 속성 게임의 이름을 지정했습니다.

    const axios = require("axios");
    const cheerio = require("cheerio");
    const express = require('express')
    
    //initializations
    const app = express()
    
    const url = "https://www.pricecharting.com/search-products?q="
    
    //middlwares
    app.use(express.json())
    
    app.post('/', async (req, res) => {
      // console.log(req.body.game)
      const game = req.body.game.trim().replace(/\s+/g, '+')
    })
    
    //server
    app.listen(3000, () => {
      console.log('listening on port 3000')
    })
    


  • 이제 우리는 req.body.game의 값을 저장할 게임이라는 상수를 만들 것입니다. 몇 가지 방법을 사용하여 final+fantasy과 같은 결과를 얻을 것입니다.
  • 먼저 trim()을 사용하여 문자열의 시작과 끝에서 공백 문자를 제거합니다.
  • 그런 다음 단어 사이의 공백을 + 기호로 replace(/\s+/g, '+') 으로 바꿉니다.

  • REST 클라이언트 2. Cheerio를 사용하여 데이터 스크랩하기

    Finally we're going to use cheerio.

    1. Now that we have our game constant we're going to use axios to make a request to our url + the game title.

    2. We are going to use a try catch block , if we get a response then we will store it in a constant named html then we will use cherrio to load that data.

    3. We are going to create a constant named games that will store this value $(".offer", html) .

    • If you open your developer tools and go to the elements tab you will that .offer class belongs to a table like the image below.

  • 이 이미지를 보면 코드에서 무슨 일이 일어나고 있는지 쉽게 이해할 수 있습니다.
  • 이제 각 제목을 얻기 위해 해당 테이블을 통해 루프를 돌고 .find(".product_name") , .find(".a") 을 사용하여 수행할 수 있습니다. 그런 다음 a 태그에서 text() 을 원합니다.

  • .
    .
    .
    
    app.post('/', async (req, res) => {
      const game = req.body.game.trim().replace(/\s+/g, '+')
      await axios(url + game)
        try {
          const response = await axios.get(url + game)
          const html = response.data;
          const $ = cheerio.load(html)
    
          const games =  $(".offer", html)
    
          games.each((i, el) => {
            const gameTitle = $(el)
            .find(".product_name") 
            .find("a")
            .text()
            .replace(/\s+/g, ' ')
            .trim()
    
            console.log(gameTitle)
          })
    
    
        } catch (error) {
          console.log(error)
        }
    })
    
    .
    .
    .
    


  • console.log(title)으로 시도하면 다음과 같은 메시지가 표시됩니다.

  • Final Fantasy VII
    Final Fantasy III
    Final Fantasy
    Final Fantasy VIII
    Final Fantasy II
    .
    .
    .
    


  • 이제 더 많은 필드를 추가하겠습니다. 이 예에서는 ID, 표지 이미지 및 시스템을 원합니다.

  • .
    .
    .
    
    app.post('/', async (req, res) => {
      const game = req.body.game.trim().replace(/\s+/g, '+')
      await axios(url + game)
        try {
          const response = await axios.get(url + game)
          const html = response.data;
          const $ = cheerio.load(html)
    
          const games =  $(".offer", html)
    
          games.each((i, el) => {
            const gameTitle = $(el)
            .find(".product_name") 
            .find("a")
            .text()
            .replace(/\s+/g, ' ')
            .trim()
    
            const id = $(el).attr('id').slice(8);
    
            //cover image
            const coverImage = $(el).find(".photo").find("img").attr("src");
    
            const system = $(el)
            .find("br")
            .get(0)
            .nextSibling.nodeValue.replace(/\n/g, "")
            .trim();
          })
    
    
        } catch (error) {
          console.log(error)
        }
    })
    
    .
    .
    .
    


    3. 응답 보내기

    Let's store this data in an array, so in order to do this, lets create an array named videoGames

    .
    .
    .
    
    const url = "https://www.pricecharting.com/search-products?q=";
    let videoGames = []
    
    
    app.post('/', async (req, res) => {
      const game = req.body.game.trim().replace(/\s+/g, '+')
      await axios(url + game)
        try {
          const response = await axios.get(url + game)
          const html = response.data;
          const $ = cheerio.load(html)
    
          const games =  $(".offer", html)
    
          games.each((i, el) => {
            const gameTitle = $(el)
            .find(".product_name") 
            .find("a")
            .text()
            .replace(/\s+/g, ' ')
            .trim()
    
            const id = $(el).attr('id').slice(8);
    
            //cover image
            const coverImage = $(el).find(".photo").find("img").attr("src");
    
            const gameSystem = $(el)
            .find("br")
            .get(0)
            .nextSibling.nodeValue.replace(/\n/g, "")
            .trim();
          })
    
          videoGames.push({
            id,
            gameTitle,
            coverImage,
            gameSystem
          })
    
          res.json(videoGames)
    
        } catch (error) {
          console.log(error)
        }
    
    })
    .
    .
    .
    

    if you try the route again you will get a result similar to the image below



    선택적으로 나는 PAL과 NTSC 시스템과 같은 타이틀을 받고 싶지 않았기 때문에 특정 시스템만 가져오도록 배열을 만들었기 때문에 기본 시스템(NTSC)을 그대로 두었습니다.

    .
    .
    .
    
    const consoles = [
      "Nintendo DS",
      "Nintendo 64",
      "Nintendo NES",
      "Nintendo Switch",
      "Super Nintendo",
      "Gamecube",
      "Wii",
      "Wii U",
      "Switch",
      "GameBoy",
      "GameBoy Color",
      "GameBoy Advance",
      "Nintendo 3DS",
      "Playstation",
      "Playstation 2",
      "Playstation 3",
      "Playstation 4",
      "Playstation 5",
      "PSP",
      "Playstation Vita",
      "PC Games",
    ]
    
    .
    .
    .
    
    app.post('/', async (req, res) => {
      .
      .
      .
    
      if (!system.includes(gameSystem)) return;
      videoGames.push({
        id,
        gameTitle,
        coverImage,
        gameSystem,
      });
      .
      .
      .
    })
    .
    .
    .
    


    4. 코드 구성

    조금 정리하자면, route라는 이름의 src에 폴더를 만든 다음 index.js라는 파일을 만듭니다. 아래 코드를 복사하여 붙여넣으세요. const {라우터} = 요구('익스프레스') const cheerio = require("cheerio"); const axios = require("축"); const 라우터 = 라우터() const URL = "https://www.pricecharting.com/search-products?q=" let videoGames = [] 상수 시스템 = [ "닌텐도 DS", "닌텐도 64", "닌텐도 NES", "닌텐도 스위치", "슈퍼 닌텐도", "게임 큐브", "위", "위 유", "스위치", "게임 보이", "게임보이 컬러", "게임보이 어드밴스", "닌텐도 3DS", "플레이 스테이션", "플레이 스테이션 2", "플레이 스테이션 3", "플레이 스테이션 4", "플레이스테이션 5", "PSP", "플레이스테이션 비타", "PC 게임", ] router.post('/', async (req, res) => { const 게임 = req.body.game.trim().replace(/\s+/g, '+') await axios(url + 게임) 노력하다 { const 응답 = await axios.get(url + 게임) const html = 응답.데이터; const $ = cheerio.load(html) const 게임 = $(".offer", html) games.each((i, 엘) => { const gameTitle = $(el) .find(".제품_이름") .을 찾다") .텍스트() .replace(/\s+/g, ' ') .손질() const id = $(el).attr('id').slice(8); const coverImage = $(el).find(".photo").find("img").attr("src"); const gameSystem = $(el) .find("br") .get(0) .nextSibling.nodeValue.replace(/\n/g, "") .손질(); if (!system.includes(gameSystem)) 반환; videoGames.push({ ID, 게임 제목, 표지 이미지, 게임 시스템, 백로그: 거짓 }); }) res.json(비디오게임) } 잡기(오류) { 콘솔.로그(오류) } }) module.exports = 라우터 이제 src index.js의 기본 파일로 돌아가서 코드를 다음과 같이 남겨둡니다. const 익스프레스 = 요구('익스프레스') //경로 const main = 요구('./routes/index') const 앱 = 익스프레스() //미들웨어 app.use(express.json()) //경로 app.use(메인) app.listen(3000, () => { console.log('포트 3000에서 실행 중인 서버') }) 사용해보시면 별 문제 없이 잘 작동하는 것을 확인하실 수 있습니다. 5. 결론

    We learned how to make a simple scraper with cheerio.

    I really hope you have been able to follow the post without any trouble, otherwise i apologize, please leave me your doubts or comments.

    I plan to make a next post extending this code, adding more routes, mongodb, and a front end.



    discord Appu#9136으로 저에게 연락할 수도 있습니다.

    You can contact me by telegram if you need to hire a Full Stack developer.

    시간 내 줘서 고마워.

    좋은 웹페이지 즐겨찾기