-
Selenium을 사용한 동적 페이지 크롤러 구현Project/DEVOOK 2022. 1. 31. 21:05
카테고리 분류기를 학습시키기 위한 데이터를 수집하기 위해 Surfit의 개발 카테고리별 글들의 URL, Title, Description을 크롤링하는 크롤러를 구현하였다. 크롤링한 데이터는 MySQL 데이터베이스에 저장되도록 하였다.
✔️ Selenium을 사용한 이유
Surfit 페이지를 보면 왼쪽 사진처럼 블로그 글이 구성되어 있고, 크롤링할 부분은 파란줄로 표시되어 있는 title과 description 부분이다.
Chrome 개발자 도구를 사용해 HTML 구성을 보면, 전체적으로 <div class="item-list"></div>로 감싸져 있고, <div class="item-area"></div> 내부에 존재한다.
하나의 글은 <div class="ct-item text"></div> 혹은 <div class="ct-item base"></div>로 감싸져 있고, 크롤링할 title과 description은 왼쪽의 파란줄로 표시되어 있는 <div class="ct-title"></div>, <div class="ct-text"></div> 부분이다.
위의 구성을 보고 처음에는 requests와 BeautifulSoup 라이브러리를 사용해 크롤러를 구현하였다.
import requests from bs4 import BeautifulSoup url = "https://www.surfit.io/explore/develop/web-dev" # HTTP GET Request headers = {"User-Agent": "Mozilla/5.0"} response = requests.get(url, headers=headers) if response.status_code == 200: html = response.text # HTML 소스 가져오기 soup = BeautifulSoup(html, "html.parser") # BeautifulSoup으로 HTML 소스를 Python 객체로 변환 title = soup.find("div", "item-list") print(title)
하지만, find()를 사용해 item-list 부분을 추출해보니 글들이 존재하지 않았다.
그 이유는 크롤링하고자 했던 영역이 동적으로 생성되는 부분이기 때문이었다.
위의 코드를 보면, requests.get()으로 웹 서버의 응답을 받고, 해당 객체의 text 속성에 접근하여 HTML 소스를 가져온다. 크롤링해야 하는 item-list 내부 부분은 추후에 동적으로 추가되므로, 현재 응답으로는 접근할 수 없었다.
위와 같은 문제는 Selenium 라이브러리의 chrome webdriver를 추가로 사용하여 해결할 수 있었다.
from selenium import webdriver from bs4 import BeautifulSoup driver = webdriver.Chrome("./chromedriver") driver.implicitly_wait(3) url = "https://www.surfit.io/explore/develop/web-dev" driver.get(url) html = driver.page_source soup = BeautifulSoup(html, 'html.parser') title = soup.find("div", "item-list") print(title) driver.quit()
💡Selenium이란?
Selenium은 주로 웹앱을 테스트하는데 이용하는 프레임워크이다. webdriver라는 API를 통해 운영체제에 설치된 Chrome등의 브라우저를 제어하게 된다. 브라우저를 직접 동작시킨다는 것은 JavaScript를 이용해 비동기적으로 혹은 뒤늦게 불러와지는 컨텐츠들을 가져올 수 있다는 것이다. Selenium을 사용해 실제 웹 브라우저를 동작시키기 때문에 JavaScript로 렌더링이 완료된 후의 DOM 결과물에 접근이 가능하다.
💡urllib.request vs. Requests
공식문서에 따르면, 더 고수준 HTTP 클라이언트 인터페이스로 Requests 패키지를 권장한다.
https://docs.python.org/ko/3/library/urllib.request.html✔️ Cursor Pagination 적용된 페이지 크롤링
Surfit 페이지의 경우 Cursor Pagination이 적용되어 있어 스크롤을 내려 페이지의 끝까지 도달해야 해당 페이지 내의 모든 데이터를 가져올 수 있다.
def web_page_scroll(driver): last_height = driver.execute_script("return document.body.scrollHeight") while True: driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(3) new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height
time.sleep(3)을 준 이유는 스크롤을 내릴 때 데이터 로딩이 발생하여 페이지 끝까지 가지 못하고 중간에 끝나는 경우도 존재하기 때문에 추가하였다.
참고)
BeautifulSoup 라이브러리 - find, find all
파이썬 웹 크롤링 - 크롤링 관련 개념 & 데이터 파싱
'Project > DEVOOK' 카테고리의 다른 글
FastText 기반 카테고리 분류 모델 만들고 배포하기 (0) 2022.05.17 데이터 점검 및 탐색 (0) 2022.02.08 머신 러닝, 자연어 처리, 데이터 분석 관련 개념 정리 (0) 2022.02.08 크롤링한 데이터를 MySQL Docker 컨테이너에 저장하기 (0) 2022.01.31 Azure 핵심 문구 추출 서비스를 사용한 키워드 추출 테스트 (0) 2022.01.29