Stage2 - Selenium을 통해 데이터 수집하기

두번째 스테이지에서는 selenium을 활용해서 네이버 지도(https://map.naver.com) 페이지에서 원하는 키워드(치킨)를 검색한 후 가게이름 / 주소 / 전화번호를 수집합니다.

Selenium으로 데이터 수집 시작하기

브라우저 자동화도구 Selenium

앞에서 동적페이지로 구성된 네이버 지도 페이지는 requests방법을 사용하지 못했기때문에 이번에는 새로운 오픈소스 패키지를 활용해 데이터를 수집하려고합니다.

selenium은 가장 유명한 브라우저 자동화도구로서 웹브라우저를 통해 할 수 있는 거의 모든 할 수 있습니다. 실제 웹브라우저를 켜는 과정을 거치기 때문에 selenium을 이용하면 동적페이지에서도 데이터를 수집할 수 있습니다.

selenium 설치

selenium은 오픈소스 패키지이므로 pip 명령어를 사용하거나, 파이참에서 selenium패키지를 설치해줍니다. 외부 패키지 설치방법 다시보기 >> 3주차 Stage1.

web driver 설치

selenium은 진짜 웹브라우저를 켜서 데이터를 수집하기 때문에 일반적으로 사용하는 Chrome이 아니라 파이썬이 열 수 있는 Chrome을 설치해줘야 합니다.

Google에 chromedriver를 검색하거나 다운로드 페이지(https://chromedriver.chromium.org/downloads)에 접속해서 내 컴퓨터에 설치된 chrome과 같은 버전의 chromedriver를 다운받습니다. 운영체제(Mac/Win/Linux)를 고려해서 다운받아야합니다.

*Chrome 버전 확인 방법. chrome://settings/help (chrome으로 접속하세요)

selenium시작하기

chromedriver 다운을 완료했다면 압축을 풀어준 후(실행은 하지 않습니다) 작업하려는 소스코드와 같은 위치에 chromediver(or chromedriver.exe)를 복사해서 붙여 넣습니다.

아래와 같이 소스코드를 작성한 후 실행해봅니다.

week6_1.py
# 네이버 지도 데이터 수집하기
from selenium import webdriver
driver = webdriver.Chrome("./chromedriver")
# 구버전 네이버지도 접속
driver.get("https://v4.map.naver.com")

새로운 Chrome 웹브라우저가 켜지면서 원하는 URL로 이동합니다. Chrome 창 위에 "Chrome이 자동화된 테스트 소프트웨어에 의해 제어되고 있습니다." 라는 메시지가 표시되는 것을 확인할 수 있습니다.

driver = webdriver.Chrome("./chromedriver")는 다운받은 웹드라이버를 통해 Chrome을 켜겠다는 의미이고 변수 driver는 켜진 웹드라이버를 가리킵니다. "./chromedriver"는 chromedriver의 위치를 의미합니다. (./ 현재 디렉토리에 있는 chromedriver)

driver.get("https://v4.map.naver.com")은 주소창에 해당하는 주소를 입력하여 URL에 접속하겠다는 의미입니다.

Selenium 사용법

설명

webdriver.Chrome("드라이버 위치")

드라이버 변수를 만듭니다. / 크롬을 켭니다.

드라이버.get("URL")

해당하는 URL에 접속합니다.

검색 절차 이해하기

selenium을 활용한 데이터 수집방식은 실제로 우리가 웹브라우저를 통해 검색을 해서 정보를 획득하는 방식과 같기 때문에 코드를 통해 데이터를 수집하기 전에 검색 절차를 살펴봅니다.

네이버 지도에서 데이터를 수집하려면 위와 같이 사람이 검색 결과를 확인하기 위해 하는 절차를 그대로 따라가야합니다.

  1. 네이버 지도 페이지에 접속

  2. 검색창에 검색어 입력하고 검색버튼 누르기

  3. 검색결과 수집하기

1. 앞에서 driver.get()을 통해 네이버 지도페이지에 접속했으므로 다음 절차부터 코드를 통해 구현해봅니다.

#2. 검색창에 검색어 입력하고 검색버튼 누르기

가장 먼저 해야할 일은 내가 원하는 검색어를 검색창에 입력하는 것입니다. selenium에서도 앞에서와 마찬가지로 선택자를 활용해서 원하는 요소를 선택해줍니다.

검사 창을 통해 쉽게 선택자를 찾을 수 있습니다.

검색창 선택자: input#search-input 검색버튼 선택자: button.spm

아래와 같이 코드를 작성한 후 실행해봅니다.

week6_2py
# 네이버 지도 데이터 수집하기
from selenium import webdriver
driver = webdriver.Chrome("./chromedriver")
# 구버전 네이버지도 접속
driver.get("https://v4.map.naver.com")
# !!!추가//네이버 지도 업데이트 후 안내메시지 끄기##########
# 무시하고 진행해주세요.
driver.find_elements_by_css_selector("button.btn_close")[1].click()
##################################################
# 검색창에 검색어 입력하기 // 검색창: input#search-input
search_box = driver.find_element_by_css_selector("input#search-input")
search_box.send_keys("치킨")
# 검색버튼 누르기 // 검색버튼: button.spm
search_button = driver.find_element_by_css_selector("button.spm")
search_button.click()

네이버 지도 페이지에 접속한 후 자동으로 치킨이라는 검색어가 검색된 것을 확인할 수 있습니다.

BeautifulSoup에서는 선택자로 하나의 데이터를 선택할 때 .select_one() 함수를 사용했습니다. selenium에서는 이것과 같은 역할을 하는 .find_element_by_css_selector() 함수를 통해 원하는 요소/데이터를 선택할 수 있습니다. 여러가지 데이터를 선택하고 싶을 때는 element를 복수형으로 바꿔주면 됩니다. (.find_elements_by_css_selector())

1주차에서 배웠던 <input>, <textarea> 등의 태그 안에 텍스트를 입력하고 싶을 때는 선택한 요소에 .send_keys() 함수를 사용하면 원하는 내용을 입력할 수 있습니다.

<button>, <a> 등의 클릭 가능한 요소를 선택한 후에는 .click() 함수를 사용해서 상호작용이 가능합니다.

selenium의 가장 큰 장점은 .find_element_by_css_selector(), .send_keys(), .click()처럼 함수의 이름이 직관적으로 만들어져있어 초심자도 쉽게 이해할 수 있습니다.

Selenium 사용법

설명

드라이버.find_element_by_css_selector("선택자")

선택자로 페이지 요소 선택하기(단일)

드라이버.find_elements_by_css_selector("선택자")

선택자로 페이지 요소 선택하기(다중)

요소.send_keys("텍스트")

해당 요소에 문자 입력하기

요소.click()

해당 요소 클릭하기

#3. 검색결과 수집하기

검색버튼을 클릭하여 검색결과가 화면에 표시된 이후에는 기존의 requests, bs4를 활용한 방법과 같은 방식으로 데이터를 수집할 수 있습니다.

  1. 컨테이너 수집

  2. 세부데이터 수집

요소별 선택자

컨테이너 선택자: div.lsnx 가게이름 선택자: dt > a 주소 선택자: dd.addr 전화번호 선택자: dd.tel

코드로 구현하기

week6_2.py
... 생략
# 검색버튼 누르기 // 검색버튼: button.spm
search_button = driver.find_element_by_css_selector("button.spm")
search_button.click()
# 컨테이너(가게 정보) 수
stores = driver.find_elements_by_css_selector("div.lsnx")
for store in stores:
# 세부 데이터 수집
name = store.find_element_by_css_selector("dt > a").text
addr = store.find_element_by_css_selector("dd.addr").text
phone = store.find_element_by_css_selector("dd.tel").text
print(name, addr, phone)

selenium을 활용한 데이터수집 방법은 정적페이지에서 데이터 수집 방법과 거의 같습니다. select/select_one 함수를 find_element_by_css_selector / find_elements_by_css_selector로 바꿔주면 됩니다.

지연시간 주기

위의 코드를 실행했을 때, 에러가 발생하거나 데이터가 수집되지 않는 경우가 있을 수 있습니다. requests를 사용하는 경우 소스코드를 한번에 가져와서 데이터를 수집하기 때문에 시간에 대한 이슈가 발생하지 않지만, selenium의 경우에는 웹브라우저를 직접 실행해서 데이터를 수집하기 때문에 컴퓨터의 성능이나 네트워크 상황에 따라 데이터를 늦게 불러오게되는 경우가 있습니다.

프로그래밍 언어는 1초에도 수백/수천줄의 코드를 실행하기 때문에 아직 데이터가 완전히 불러오기 전에 데이터를 읽어오려고한다면 정상적으로 데이터를 수집할 수 없게 됩니다.

네이버 지도 페이지에서 지연시간이 필요한 경우

네이버 지도 검색에서는 검색버튼을 누른 후, 검색결과를 확인하기까지 짧지만 데이터를 로딩하는 시간이 필요합니다. 인터넷 상황이 좋지 않은 곳에서 확인하면 명확히 알 수 있습니다.

아래와 같이 파이썬 내부라이브러리 time을 활용해서 데이터 수집 중 지연시간을 줄 수 있습니다.

week6_2.py
# 네이버 지도 데이터 수집하기
from selenium import webdriver
##################################################
# 파이썬 내부 라이브러리 time을 사용합니다.
# time: 시간과 관련된 여러가지 기능을 포함합니다.
import time
##################################################
driver = webdriver.Chrome("./chromedriver")
# 구버전 네이버지도 접속
driver.get("https://v4.map.naver.com")
# !!!추가//네이버 지도 업데이트 후 안내메시지 끄기##########
# 무시하고 진행해주세요.
driver.find_elements_by_css_selector("button.btn_close")[1].click()
##################################################
#3. 검색창에 검색어 입력하기 // 검색창: input#search-input
search_box = driver.find_element_by_css_selector("input#search-input")
search_box.send_keys("치킨")
#4. 검색버튼 누르기 // 검색버튼: button.spm
search_button = driver.find_element_by_css_selector("button.spm")
search_button.click()
##################################################
# 1초의 지연시간을 줍니다.
time.sleep(1)
##################################################
# 컨테이너(가게 정보) 수
stores = driver.find_elements_by_css_selector("div.lsnx")
for store in stores:
# 세부 데이터 수집
name = store.find_element_by_css_selector("dt > a").text
addr = store.find_element_by_css_selector("dd.addr").text
phone = store.find_element_by_css_selector("dd.tel").text
print(name, addr, phone)

time은 시간과 관련된 여러가지 기능을 포함한 라이브러리입니다. time라이브러리의 sleep() 함수를 사용하면 괄호 안에 입력한 시간동안 다음 코드를 실행하지 않고 기다립니다.

사용법

설명

time.sleep()

입력한 시간(sec) 동안 시간을 지연시킵니다.

*웹페이지 중에 짧은 시간 동안 너무 많은 데이터를 요청하면 오류를 발생시키는 페이지도 있습니다. 이럴 때도 time.sleep()을 유용하게 사용할 수 있습니다. **참고하면 좋은 내용: implicitly wait, explicitly wait

추가)드라이버 닫기

크롬이 엄청 많이 켜진다.

파이썬에서 selenium 웹드라이버를 계속적으로 실행하면 웹드라이버가 계속해서 쌓이게 됩니다. 데이터 수집이 종료된 후에 브라우저를 닫고 싶다면 프로그램 종료 전에 아래 코드를 추가해주시면 됩니다.

driver.close()