728x90

안녕하십니까, 간토끼입니다.

이전까지의 포스팅에서는 requests와 BeautifulSoup을 이용해 크롤링하는 방법에 대해서 다루어봤습니다.이번에는 Selenium이라는 라이브러리를 이용해 크롤링하는 방법에 대해서 다뤄보겠습니다.


- 동적 페이지 vs 정적 페이지
우리가 이전까지 다루었던 웹페이지를 한번 살펴보죠.

다음 검색에 '간토끼 Data'를 검색하면 다음과 같이 검색 결과가 나오는데요.
URL을 보면 q='검색어' 가 입력되는 걸 알 수 있습니다.
이러한 특성을 이용해 이전 포스팅에서 input으로 우리가 원하는 검색어를 입력해 그에 맞는 결과를 크롤링하였죠.

이번엔 카카오 맵을 한번 보시죠.
분명 url 상에는 아무런 검색어가 입력되지 않고도, 웹페이지 내에서 검색어를 별도로 입력했더니 검색결과가 나타나는 것을 알 수 있습니다.
만약 이 카카오맵상에 출력되는 결과를 크롤링하기 위해 이전 포스팅에서 했던 것과 같은 방식으로 시도하면,
아마 아무런 결과도 크롤링하지 못할 것입니다.


이러한 현상은 웹페이지 형식의 차이에 의해 발생하는데요.
다음 검색 결과처럼 URL에 따라 정해진 페이지를 불러오는 것을 정적(Static)페이지라고하며, 다음 지도처럼 URL에 관계없이 웹페이지 위에서 데이터를 불러오는 방법을 사용하는 것을 동적(dynamic)페이지라고 합니다.
즉, 동적 페이지는 페이지에 접속하면 유저의 행동결과에 따라 소스코드가 변화하므로, 기존과 다른 방식으로 접근해야 합니다.

우리는 이번 포스팅에서 이러한 동적 페이지에서도 원하는 정보를 크롤링할 수 있는 방법에 대해서 다뤄보겠습니다.

1. Selenium 라이브러리 설치

# terminal 혹은 Anaconda Prompt 실행

pip install selenium


2. Chrome Driver 설치


이후 Google에 chromedriver를 검색하거나 다운로드 페이지(https://chromedriver.chromium.org/downloads)에 접속해서 내 컴퓨터에 설치된 chrome과 같은 버전의 chromedriver를 다운받습니다.
이는 파이썬에서 크롬에 접속할 수 있도록 만들어줍니다.

다운을 받으셨다면 파이썬에서 현재 작업하고 있는 working directory에 다운 받은 chromedriver.exe 파일을 넣어줍니다.
exe 파일은 따로 실행하지 않으셔도 무방합니다.
(반드시 현재 작업공간으로 설정되어있는 경로에 driver 파일을 넣어주셔야 합니다.)

3. Selenium 실행

# selenium 불러오기
from selenium import webdriver
import time

# chrome창(웹드라이버) 열기
driver = webdriver.Chrome("./chromedriver")

# 실행할 웹페이지 불러오기(구글 지도 예시)
driver.get("https://www.google.com/maps/")


여기까지 하면 selenium을 실행할 준비를 모두 마쳤습니다.
구글 지도를 예시로 한번 살펴보죠.

먼저 selenium의 작동 매커니즘을 이해하려면, 동적 페이지에서의 우리의 동작을 떠올려봐야 합니다.
(1) 구글 지도 웹사이트를 띄운다.
(2) 검색창에 우리가 검색하고자 하는 키워드를 입력한다.
(3) 검색 버튼을 클릭한다.

이 3가지 동작을 순서대로 실행하면 비로소 우리가 찾는 키워드에 맞게 검색 결과가 노출되겠죠.
selenium으로도 이에 맞게 실행해줘야 합니다.

# 선택자로 페이지 요소 선택하기(단일)
driver.find_element_by_css_selector("선택자")

# 선택자로 페이지 요소 선택하기(다중)
driver.find_elements_by_css_selector("선택자")

# 해당 요소에 문자 입력하기(ex. 버튼)
button.send_keys("텍스트")

# 해당 요소 클릭하기
button.click()

선택자이전에 정적 페이지에서 HTML 구조를 살펴보고 찾은 것과 동일하게 적용하면 됩니다.
(잘 모르시겠으면 이전 포스팅을 참고해주세요.)
그리고 요소는 버튼(Button)과 같이 클릭 등이 가능한 것을 의미합니다. (검색버튼처럼요.)

예를 들어 '카페'를 입력한다고 가정하면 코드는 다음과 같습니다.

# 검색창에 "카페" 입력하기
searchbox = driver.find_element_by_css_selector("input#searchboxinput")
searchbox.send_keys("카페")

# 검색버튼 누르기
searchbutton = driver.find_element_by_css_selector("button#searchbox-searchbutton")
searchbutton.click()


만약 위의 코드를 실행했을 때, 에러가 발생하거나 데이터가 수집되지 않는 경우가 있을 수 있습니다.
requests를 사용하는 경우 소스코드를 한번에 가져와서 데이터를 수집하기 때문에 시간에 대한 이슈가 발생하지 않지만,
selenium의 경우에는 웹브라우저를 직접 실행해서 데이터를 수집하기 때문에 컴퓨터의 성능이나 네트워크 상황에 따라 데이터를 늦게 불러오게되는 경우가 있습니다.
우리가 검색 버튼을 누르면 네트워크 상황에 따라 약 2초 정도 기다린 후 로딩이 되는 것처럼요.

이때 time 이란 기본 라이브러리를 이용해 웹페이지에서 정상적으로 검색 결과를 불러올 수 있도록 의도적으로 쉬어줘야 합니다.

import time

# 의도적으로 3초 쉬어주기
time.sleep(3)



종합적으로 예제를 살펴보죠.
구글 지도에서 '카페'를 검색한 결과를 수집하는 코드입니다.

from selenium import webdriver
import time

# 크롬창(웹드라이버) 열기
driver = webdriver.Chrome("./chromedriver")

# 구글 지도 접속하기
driver.get("https://www.google.com/maps/")

# 검색창에 "카페" 입력하기
searchbox = driver.find_element_by_css_selector("input#searchboxinput")
searchbox.send_keys("카페")

# 검색버튼 누르기
searchbutton = driver.find_element_by_css_selector("button#searchbox-searchbutton")
searchbutton.click()

# 여러 페이지(999)에서 반복하기
for i in range(999):
    # 시간 지연
    time.sleep(3)

    # 컨테이너(가게) 데이터 수집 // div.section-result-content
    stores = driver.find_elements_by_css_selector("div.section-result-content")

    for s in stores:
        # 가게 이름 데이터 수집 // h3.section-result-title
        title = s.find_element_by_css_selector("h3.section-result-title").text

        # 평점 데이터 수집 // span.cards-rating-score
        # 평점이 없는 경우 에러 처리
        try:
            score = s.find_element_by_css_selector("span.cards-rating-score").text
        except:
            score = "평점없음"

        # 가게 주소 데이터 수집 // span.section-result-location
        addr = s.find_element_by_css_selector("span.section-result-location").text

        print(title, "/", score, "/", addr)

    # 다음페이지 버튼 클릭 하기
    # 다음페이지가 없는 경우(데이터 수집 완료) 에러 처리
    try:
        nextpage = driver.find_element_by_css_selector("button#n7lv7yjyC35__section-pagination-button-next")
        nextpage.click()
    except:
        print("데이터 수집 완료.")
        break

# 크롬창 닫기
driver.close()


1) 검색 결과가 노출되면 순차적으로 수집한 후
2) 수집이 완료되면 다음 페이지로 넘어가서(1->2) 순차적으로 수집합니다.
3) 만약 평점을 수집할 때 평점이 없는 카페가 있어 에러가 발생한다면, "평점없음"으로 기록될 수 있도록 error 처리를 합니다.
4) 다음 페이지로 넘어갈 수 없어 에러가 발생한다면, "데이터 수집 완료"를 print하고 크롤링을 종료합니다.
5) 코드가 모두 실행되어 종료되면 driver.close( ) 를 이용해 selenium에 의해 실행된 웹페이지 창을 닫아줍니다.

위 예제를 응용하면 여러 웹페이지에서 활용 가능한 자동화 서비스도 간단하게 구축할 수 있습니다.
매일 반복되는 업무를 해야 하는 분이라면 코드로 이를 구축해놓고 실행만 해주면 되겠죠?


크롤링은 여기까지만 다뤄보고요.
다음 포스팅에서는 다른 라이브러리를 살펴보도록 하겠습니다.


감사합니다.
잘 읽으셨다면 게시글 하단에 ♡(좋아요) 눌러주시면 감사하겠습니다 :)
(구독이면 더욱 좋습니다 ^_^)



- 간토끼(DataLabbit)
- University of Seoul
- Economics, Data Science

728x90

+ Recent posts