본문 바로가기

프로젝트/뉴스스탠드

데이터 크롤링 및 json-server 활용

데이터  크롤링

- 뉴스스탠드 프로젝트는 네이버의 뉴스스탠드를 클론 코딩하는 프로젝트였다.

- 처음 기획서를 보고 네이버의 뉴스 데이터를 어떻게 가져올 수 있을까 대한 고민이 생겼고, 동료의 도움으로 데이터 크롤링에 대해서 학습하고 사용했다.

- 데이터 크롤링은 웹상의 정보들을 탐색하고 수집하는 작업을 의미하며 주로 규칙에 따라 자동으로 웹 문서를 탐색하는 컴퓨터 프로그램, 웹 크롤러(Crawler)를 사용한다.

- 나는 네이버 PC 메인 화면에서 개발자 도구에서 DOM 요소를 선택하여 정보를 수집하는 방법을 사용했고, 실제 프로젝트에서 사용한 크롤링 코드와 db.json의 모습은 다음과 같다.

// 데이터 크롤링 코드
const result = [];
// DOM 요소를 선택하여 정보를 수집
document.querySelector('.ico_btn').addEventListener('click', () => {
  const logoImgSrc = document.querySelector('.link_media img').src;
  const pressName = document.querySelector('.link_media img').alt;
  const category = document.querySelector('.option_on a').dataset.clk;
  const updateTime = document.querySelector('.time').textContent;
  const mainNewsImg = document.querySelector('.thumb img').src;
  const mainNews = document.querySelector('.title').textContent;
  const noticeMessage = document.querySelector('.notice_msg').textContent;
  const subNewsList = [...document.querySelectorAll('.news_item')].map(
    (subNews) => subNews.innerText
  );

  // 프로젝트에서 사용할 데이터 형태로 가공
  const obj = {
    logoImgSrc,
    pressName,
    category,
    updateTime,
    mainNewsImg,
    mainNews,
    noticeMessage,
    subNewsList,
  };

  result.push(obj);
  console.log(result);
});

* 네이버 PC 메인 화면이 2023년 5월 개편됨에 따라, 현재는 사용할 수 없는 코드일 수 있습니다.

// db.json
{
"NSSectionData": [
    {
      "logoImgSrc": "https://s.pstatic.net/static/newsstand/up/2021/0819/nsd151219656.png",
      "pressName": "데일리임팩트",
      "category": "종합/경제",
      "updateTime": "2023.04.15. 17:10\n편집",
      "mainNewsImg": "https://s.pstatic.net/static/newsstand/2023/0415/article_img/new_main/9234/171250_001.jpg",
      "mainNews": "尹 방미 경제사절단...누가 가서 무슨 일 할까?",
      "noticeMessage": "\n데일리임팩트 언론사에서 직접 편집한 뉴스입니다.\n",
      "subNewsList": [
        "코리안리 10년만에 금감원 검사 받는 특별한 이유",
        "루이뷔통 덕 봤나...명품주 날자 프랑스 증시 '훨훨'",
        "현대그린-신세계푸드-아워홈을 바라보는 불안한 시선들",
        "20억 넘는 보험사 '연봉킹' 3인, 같은 점과 다른 점은",
        "현대차·기아, 아시아개발은행 연차총회 의전용 전기차 지원",
        "KT, 소상공인 온라인 마케팅 돕는다"
      ]
    },
    {
      "logoImgSrc": "https://s.pstatic.net/static/newsstand/2020/logo/light/0604/922.png",
      "pressName": "이투데이",
      "category": "종합/경제",
      "updateTime": "2023.04.15. 13:49\n편집",
      "mainNewsImg": "https://s.pstatic.net/static/newsstand/2023/0415/article_img/new_main/9114/135448_001.jpg",
      "mainNews": "“시장 커지는데…” 인재 확보에 사활 건 K-배터리",
      "noticeMessage": "\n이투데이 언론사에서 직접 편집한 뉴스입니다.\n",
      "subNewsList": [
        "기시다 日총리 연설 전 폭발음…\"총리는 대피해 무사\"",
        "은행 점포 3년째 ‘세 자릿수 감소’…해결책은",
        "머스크, ‘오픈 AI 대항마’ 새 AI 스타트업 설립 추진",
        "간호법 놓고 맞서는 여야…27일까지 합의 가능할까",
        "“회사 점심시간, 집에 다녀와도 될까요?”…네티즌 생각은",
        "“교촌치킨 대체품 찾아요”…가격 인상에도 기술이 필요하다?"
      ]
    },
   ...
   ]
 }

json-server 활용

- json-server는 json 파일을 사용하여 간단한 시뮬레이션을 위한 REST API Mock server를 구축할 수 있는 툴이다.

- 한마디로 프론트엔드에서 프로젝트를 진행할 때, 백엔드 없이 가상의 db와 서버를 구축하는 툴이다.

- 나는 개인 프로젝트에서 크롤링으로 수집한 데이터들을 사용하기 위해 json-server를 활용했다.

- json-server의 사용법과 실제 코드는 다음과 같다.

 

1. json-server 설치

- 다음 명령어를 통해 json-server를 설치한다.

$ npm install json-server --save-dev

2. db.json 만들기

- 개발자 도구에서 DOM 요소를 선택해 수집한 데이터들을 db.json에 저장했다.

- db.json 파일은 데이터베이스 역할을 한다.

// db.json
{
"NSSectionData": [
    {
      "logoImgSrc": "https://s.pstatic.net/static/newsstand/up/2021/0819/nsd151219656.png",
      "pressName": "데일리임팩트",
      "category": "종합/경제",
      "updateTime": "2023.04.15. 17:10\n편집",
      "mainNewsImg": "https://s.pstatic.net/static/newsstand/2023/0415/article_img/new_main/9234/171250_001.jpg",
      "mainNews": "尹 방미 경제사절단...누가 가서 무슨 일 할까?",
      "noticeMessage": "\n데일리임팩트 언론사에서 직접 편집한 뉴스입니다.\n",
      "subNewsList": [
        "코리안리 10년만에 금감원 검사 받는 특별한 이유",
        "루이뷔통 덕 봤나...명품주 날자 프랑스 증시 '훨훨'",
        "현대그린-신세계푸드-아워홈을 바라보는 불안한 시선들",
        "20억 넘는 보험사 '연봉킹' 3인, 같은 점과 다른 점은",
        "현대차·기아, 아시아개발은행 연차총회 의전용 전기차 지원",
        "KT, 소상공인 온라인 마케팅 돕는다"
      ]
    },
   ...
   ]
 }

 

3. json-server 실행

- json-server를 실행하기 전에 package.json 파일에 scripts에 json-server를 실행하는 명령어를 작성했다.

// package.json
{
  "scripts": {
    "compileSass": "node-sass sass/main.scss style.css -w",
    "server": "json-server -p 3001 --watch db.json"
  },
  "dependencies": {
    "json-server": "^0.17.3"
  }
}

- "-p 3001" 옵션은 json-server가 3001 포트에서 실행되도록 저장한다.

- "--watch db.json" 옵션은 json-server가 db.json 파일을 감시하도록 한다.

- 위와 같이 json-server를 실행하는 명령어를 입력하면, 아래와 같이 json-server가 실행되었음을 확인할 수 있다.

4. json-server를 활용하여 비동기 통신하기

- json-server를 통해 db.json에 저장된 데이터를 비동기 통신으로 가져오는 실제 코드이다.

- json-server의 포트를 3001로 저장했기 때문에, NSSectionData 불러오는 api 주소는 http://localhost:3001/NSSectionData가 된다.

// 비동기 통신을 위한 fetcher 유틸 함수 작성
// url를 입력 받아서 비동기 함수를 반환한다.
// 필요한 데이터 타입, 콜백함수를 전달 받는다.
const fetcher = (url) => {
  return async (type, cb) => {
    try {
      const response = await fetch(`${url}${type}`);
      const data = await response.json();
      return cb(data);
    } catch (error) {
      console.error(error);
    }
  };
};

// API 주소 http://localhost:3001을 전달하여 반환된 함수를 dataFetcer에 저장한다.
const dataFetcher = fetcher(API_BASE_URL);

// dataFetcher 함수 전달 
const NSSectionCurViewModel = new NSSectionCurViewStateModel(dataFetcher);

// dataFetcher 함수 실행
export default class NSSectionCurViewStateModel extends Observer {
  constructor(dataFetcher) {
    super();
    this._curViewState = {
      render: RENDER_STATE.NOT_READY,
      gridOrList: VIEW_STATE.GRID,
      allOrSub: VIEW_STATE.ALL,

      index: 1,
      curListCategory: null,
      curListSubPress: null,
    };
    this._dataFetcher = dataFetcher;
    this._allPressData = {};
    this._gridPressData = [];
    this._subPressData = [];
    this._allCategory = [];
  }
  ...
  async getGridAllPressData() {
    const start = (this._curViewState.index - 1) * NS_SECTION_INFO.GRID_ALL.PAGE_SIZE;
    const end = start + NS_SECTION_INFO.GRID_ALL.PAGE_SIZE;

    if (this._gridPressData.length === 0) {
      // type과 콜백함수를 전달하여 dataFetcher 함수 실행
      const allData = await this._dataFetcher(API_PATH.NS_SECTION, this.getAllData.bind(this));
      this.setAllPressData(allData);
      this.setGirdPressData(allData);
    }
    return [...this._gridPressData.slice(start, end)];
  }
  ...
}

참고: https://poiemaweb.com/json-server

 

'프로젝트 > 뉴스스탠드' 카테고리의 다른 글

[기능 구현] requestAnimationFrame을 활용한 애니메이션  (0) 2024.01.25
Sass/Scss  (0) 2024.01.25
옵저버 패턴  (0) 2024.01.23