반응형

개요

 

이번에는 Node.js를 사용하여 특정 웹사이트의 정보를 크롤링하는 방법을 알아보도록 하겠습니다.

 


설명

 

저는 코로나 사이트에 들어가서 총 확진자의 수를 가져오도록 하겠습니다.

http://ncov.mohw.go.kr/bdBoardList_Real.do?brdId=1&brdGubun=11&ncvContSeq=&contSeq=&board_id=&gubun=

 

해당 사이트에 접속후 F12를 눌러 원하고자 하는 곳을 쭉 따라가면서 경로를 기억해 둡니다.

 


Switch case 문을 이용

 

저는 Switch case 문을 통해서 원하는 값을 찾도록 하겠습니다.

 

여기서. first는 가장 앞의 값을 가져오는 구문이며 쭉 찾아나가 dd속의 14203을 찾아나갑니다.

 

이렇게 받아온 정보를 server.js에서 배치 크롤러를 통해서 1분마다 정보를 가져오도록 합니다.

 

 

이렇게 크롤링해서 가져온 정보를 통해 우리는 이정보를 json 형태로 서버 쪽으로 던져주면 됩니다. 

여기서 중요한 점이 우리가 크롤링을 비동기형태로 받아오고 있기 때문에 서버로 던져주는 것도 비동기 형식으로 던져주면 됩니다.

async와 await를 사용하여..

 

여기서 text는 우리가 크롤링해온 정보인 14023입니다.

 

우리가 5000번 포트를 서버로 이용하기 때문에 이제 저희가 던진 정보가 제대로 잘 들어갔는지 확인을 하러 갑니다.

 

우리가 서버로 던진 정보가 json 형태로 잘 저장되어 있는 것을 볼 수 있습니다.

이제 이러한 정보를 React의 App.js로 값을 전달해보도록 하겠습니다.

 


값 확인

 

우선 받아온 정보를 모듈로 만들어 사용하기 위해서 Poster라는 모듈을 만들어 줍니다.

그리고 여기서 React의 컴포넌트를 생성시 생명주기 순서가 있는데 

생명주기 순서 : constructor(생성자) -> componentWillMount -> render

이렇게 됩니다. 이것을 명심하고 만들게 되면...

 


결과

 

 

최종적으로 값을 이렇게 가져오는 것 을 볼 수 있습니다.

 


crawl.js

 

const axios = require("axios");
const cheerio = require("cheerio");

let html = "";

async function getHtml() {
  try {
    return await axios.get(
      "http://ncov.mohw.go.kr/bdBoardList_Real.do?brdId=1&brdGubun=11&ncvContSeq=&contSeq=&board_id=&gubun="
    );
  } catch (error) {
    console.error(error);
  }
}

async function getNews() {
  if (!html) {
    html = await getHtml();
  }

  const $ = cheerio.load(html.data);
  let smp = {};
  $("#content .caseTable .ca_body li")
    .first("dl")
    .each(function (index, elem) {
      switch ($(this).find("dt").text().trim()) {
        case "누적":
          smp = $(this)
            .find("dd")
            .text()
            // .replace(/([\t|\n|\s])/gi, "");
          break;
      }
    });

  return smp;
}

module.exports = { getNews };

 


server.js

 

const express = require("express");
const { getNews } = require("./crawl.js");
const bodyParser = require("body-parser");
const app = express();
const port = process.env.PORT || 5000;
const cron = require("node-cron");
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));

async function handleAsync() {
  const sum = await getNews();
 // console.log(sum);
  return sum;
}
cron.schedule("*/1 * * * *", async () => {
  console.log("running a task every two minutes");
  await handleAsync();
});


// app.use('/api/crwal',async(req,res) => {
//   const text = await handleAsync();
//   console.log(text);
//   res.json([{text: text},
//             {id : 1}]
//     );
// })

app.get('/api/crwal', async(req, res) => {
  const text = await handleAsync();
  
  res.send([
    
    { 'id' : 1,
      'text' : text
    }

  ]);
});

app.listen(port, () => console.log(`Listening on port ${port}`));

 


/compoents/posts.js

 

import React, { Component } from 'react';

class Posts extends Component {
    /* 컴포넌트 생성시 */
    /* 생명주기순서 : constructor(생성자) -> componentWillMount -> render */
    constructor(props) {
        super(props);
        this.state = {
            crwal: []
        }
    }
    componentWillMount() {
        fetch('api/crwal')
            .then(res => res.json())
            .then(data => this.setState({
                crwal: data
            }));
    }
    render() {
        const { crwal } = this.state;
        const postsList = crwal.map((post) => (
            <div key={post.id} id={post.id}>
                
                <h4>{post.text}</h4>
            </div>
        ));
       
        return (
            
            <div >
                <h2>확진자 현황</h2>
            <table>
                <tr>
                    <td><h3>총 확진자 = </h3></td>
                    <td>{postsList}</td>
                </tr>
            </table>
            </div>
        );
    }
}
export default Posts;

 


App.js

 

import React, { Component, useEffect } from "react";
import Appbar from "./components/Appbar";
import Scroller from "./components/Scroller";
import { withStyles } from "@material-ui/core/styles";
import { json } from "body-parser";
import Posts from "./components/posts";


const styles = (theme) => ({
  firstDiv: {
    backgroundColor: "#81c147",
    width: "100vw",
    height: "100vh",
  },
  secondDiv: {
    backgroundColor: "#1176a7",
    width: "100vw",
    height: "100vh",
  },
  thirdDiv: {
    backgroundColor: "#228f76",
    width: "100vw",
    height: "100vh",
  },
});

class App extends Component {
  
  render() {
    const { classes } = this.props;
    return (
      <div>
        <div id="section1" className={classes.firstDiv}>
          <Appbar />
          <Scroller />
          <Posts/>
        </div>
        <div id="section2" className={classes.secondDiv}></div>
        <div id="section3" className={classes.thirdDiv}></div>
      </div>
    );
  }
}

export default withStyles(styles)(App);

 


 

반응형

+ Recent posts