무언가 구현을 하다보면 어딘가 있는 정보를 끌어와서 이용을 해야할 때가 있다.
그러한 행위를 스크래핑, 크롤링이라 부르는데
한번만 가져오는 것을 스크래핑
반복해서 가져오는 것을 크롤링이라고 부른다.
작업을 할 때 도움을 주는 라이브러리가 당연히 있고
스크래핑은 cheerio
크롤링은 Puppeteer 가 존재한다.
이게 뭔가? 라는 느낌도 있겠지만 우리는 모르는 사이에 이것을 이용하고 있다.
바로 채팅기능이 포함되어있는 앱(카톡,디코)에서 사이트의 링크를 걸 경우 미리보기가 제공이 되는 것을 볼 수 있는데
그 미리보기는 HTML 문서 중 HEAD태그 속에 있는 mete태그 속 og의 내용을 스크래핑으로 가져온 것이다.
이것은 페이스북에서 시작을 하긴 했지만 클라이언트(사용자)들에게 주는 만족감이 좋기 때문에 모든 사이트에서 활용을 하고 있다.
이제는 링크를 받았을 경우에 미리보기가 없으면 불안한 느낌을 느끼기도 하고, 특정 프로그램에서는 검증되지 않는 사이트라며 필터링을 해주는 곳도 존재한다.
위에서 하는 작업은 프론트쪽에서 하는 것이고, 백엔드에서는 어떤식으로 활용을 하게 되는걸까?
사이트의 메인 홈페이지의 경우에는 프론트쪽에서 작업을 해주겠지만,
메인 홈페이지가 아닌 내용들이 언제나 바뀌는 페이지는 모두 작업을 해줄 수 없기 때문에
api로 자동화를 시켜주는 작업이 필요하다.
이렇게 특정 상품이 링크로 들어왔을 때, 내용의 일부만 가지고 구성을 해줘야할 경우 스크래핑
을 활용하여
데이터의 일부로 사진과 링크 등의 정보들을 만들어서 클라이언트(사용자)에게 보낼 수 있다.
크롤링은 주기적으로 스크래핑을 한다고 생각하면 조금은 쉽게 생각할 수 있다.
그리고 특정 사이트의 정보를 주기적
으로 가져오는 것이기에 그 사이트의 서버에 과부화를 줄 수 있기에 주의해야한다.
이러한 이유때문에 크롤링을 거부하는 곳도 있는데 주소창에 /robots.txt라고 치면
이 주소는 하지마라, 해도 된다 이런식으로 명시해놓은 파일이 존재한다.
미니프로젝트가 거의 다 완성된 상태라서, 미니프로젝트의 코드를 가져와서 리뷰하는 방식으로 진행하려고 한다.
import axios from "axios"; import Cheerio from "cheerio"; export async function ogGet(user) { user.includes("http") ? user : (user = "https://" + user); let obj = {}; const page = await axios.get(user); const $ = Cheerio.load(page.data); $("meta").each((_, el) => { if ($(el).attr("property")) { const key = $(el).attr("property").split(":")[1]; const value = String($(el).attr("content")); obj[key] = value; } }); return obj; }
내가 og태그에 들어가있는 내용을 담아오기 위해 작성한 내용이다.
여기서 크게 어려웠던 것은 별로 없었다. 근데 제일 큰 문제는 바로 주소
였다.
그냥 작성을 해서 코드를 돌리면 url은 담아올 수 없다. 문자열의 형태로 바꿔라 라는 에러를 무한반복으로 내뱉는다.
저 에러를 잡는게 진짜 진짜 너무 오래걸렸는데 그냥 그 값에 강제 형변환으로 선언을 해주면 되는 것이더라...^^
아무튼 위와 같은 방식으로 사용했다.
import puppeteer from "puppeteer"; async function startCrawling() { const browser = await puppeteer.launch({ headless: true }); // 브라우저가 보이게 한다 const page = await browser.newPage(); // 새로운 브라우저 켜기 await page.goto(""); // 페이지 이동 await page.waitForTimeout(1000); for (let i = 1; i <= 10; i++) { // 반복문 돌면서 값 여러개 가져오기 await page.waitForTimeout(500); const img = await page.$eval(,(el) => el.src); const name = await page.$eval(,(el) => el.textContent); } }
이런식으로 구성을 한다.
엄청 자기만의 메소드가 존재하고, js의 메소드들을 사용할 수 있게 하는 함수도 있기 때문에
사용하려고 마음을 먹으면 좀...많이 복잡할 것 같다.