데이터 크롤링
- 뉴스스탠드 프로젝트는 네이버의 뉴스스탠드를 클론 코딩하는 프로젝트였다.
- 처음 기획서를 보고 네이버의 뉴스 데이터를 어떻게 가져올 수 있을까 대한 고민이 생겼고, 동료의 도움으로 데이터 크롤링에 대해서 학습하고 사용했다.
- 데이터 크롤링은 웹상의 정보들을 탐색하고 수집하는 작업을 의미하며 주로 규칙에 따라 자동으로 웹 문서를 탐색하는 컴퓨터 프로그램, 웹 크롤러(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 |