ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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)을 준 이유는 스크롤을 내릴 때 데이터 로딩이 발생하여 페이지 끝까지 가지 못하고 중간에 끝나는 경우도 존재하기 때문에 추가하였다. 

     

     

    참고)

    파이썬으로 크롤링하는데 값이 안 읽어와질때 해결법

    Selenium을 사용한 크롤러1

    Selenium을 사용한 크롤러2

    BeautifulSoup 라이브러리 - find, find all

    Selenium 웹페이지 스크롤하기

    파이썬 웹 크롤링 - 크롤링 관련 개념 & 데이터 파싱

     

     

     

     

     

    댓글

Designed by Tistory.