개발자/파이썬

파이썬 (Selenium) 로딩까지 기다림 (feat. WebDriverWait)

june__kim 2021. 1. 1. 21:03

파이썬 셀레니움 로딩까지 기다림 Waits Selenium (feat. WebDriverWait)

 

2020/12/31 - [개발자/파이썬] - 파이썬 (Python) Selenium (기본, 네이버 로그인)

 

 

저번 글에서 Selenium의 사용방법에 대해서 글을 썼었다.

 

이번에는 웹 스크래핑을 하다보면 필요한 도구(?) 몇 가지에 대해 글을 써보려고 한다.

 

WebDriverWait를 이용한 Explicit Waits

우리가 웹 스크래핑을 하다보면, 로딩시간이 있다.

즉, 어떤 페이지가 완전히 Load되기까지 일정 시간을 기다려야한다.

 

ex) 비행기항공권(네이버 or 스카이스캐너 등등)

(아래의 그림처럼)

네이버항공권 예제

완전히 페이지가 Load되고 나서 어떤 정보들을 긁어 올 수 있는데,

이때 사용되는 것이 Webdriver이다.

 

Selenium 공식 문서에 존재하는 예제를 통해 이해해보자.

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

driver = webdriver.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
    element = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((By.ID, "myDynamicElement"))
    )
finally:
    driver.quit()

(출처: selenium-python.readthedocs.io/waits.html

 

 

 

 

 

 

 

이 코드의 의미를 살펴보면,

WebDriverWait(driver, 10)

: WebDriverWait을 통해 driver를 "최대" 10초동안 기다린다. 

(이때 10초를 넘기면 NoSuchElementException, ElementNotVisibleException과 같은 에러가 발생한다.)

이런 에러가 뜬다면, 한번 Waits을 해보자)

 

.until(EC.presence_of_element_located((By.ID, "myDynamicElement"))

: 언제까지? -> ID가 "myDynamicElement"인 엘리먼트가 나올 때까지

(이때 해당 엘리먼트가 나오면, EC에서 True를 리턴한다.)

EC에서 presence_of_element_located 말고도 다양한 메소드를 제공한다.(ex. element_to_be_clickable() 등등..)

 

즉, ID가 myDynamicElement인 element가 나올 때까지 최대 10초를 기다린다.

 

이때, ID 이외에도 XPATH, CLASS_NAME, LINK_TEXT 등등을 이용해 Explicit Waits을 구현 할 수 있다.

그냥 저 틀을 알아두면 편할 것 같다.

 

이를 통해, 네이버항공권을 이용해 스크래핑한 예제코드를 보자.

from selenium import webdriver

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

browser = webdriver.Chrome("각자의 경로")
browser.maximize_window() # 창 최대화

url = "https://flight.naver.com/flights/"

browser.get(url) # url로 이동

# 가는 날 선택 클릭
browser.find_element_by_link_text("가는날 선택").click()

# 이번달 27일, 28일 선택

browser.find_elements_by_link_text("27")[0].click() # 가는 날짜
browser.find_elements_by_link_text("28")[1].click() # 오는 날짜

browser.find_element_by_xpath("//*[@id='recommendationList']/ul/li[1]/div/dl").click() # 제주도 선택

browser.find_element_by_link_text("항공권 검색").click() # 항공권 검색 클릭

try:
    # 브라우저를 최대 10초까지 기다린다. (xpath의 값이 나올때까지)
    elem = WebDriverWait(browser, 20).until(
    	EC.presence_of_element_located((By.XPATH,"//*[@id='content']/div[2]/div/div[4]/ul/li[1]"))
    )
    print(elem.text)
finally:
    browser.quit()

 

cf. Explicit Waits vs Implicit Waits vs time.sleep

Selenium에서 제공하는 Waits에서 Implicit Waits이 있는데, 

이 경우엔, 일정 시간만큼을 기다리는 것이다. (주로 페이지 로딩 시간을 기다림)

즉, Explicit Waits의 경우, 어떤 조건을 주는 반면, Implicit Waits의 경우 일정 시간만큼 기다린다.

그리고 일정시간(ex 10초)을 넘겨버리면 마찬가지로 NoSuchElementException, ElementNotVisibleException 등의 에러를 띄운다.

from selenium import webdriver

driver = webdriver.Firefox()
driver.implicitly_wait(10) # seconds
driver.get("http://somedomain/url_that_delays_loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")

이때, Selenium에서 제공하는 implicitly_wait과 time모듈에서 제공하는 time.sleep()이 헷갈릴 수도 있는데,

time.sleep(10)의 경우, 페이지가 로딩되건 뭐가 되건 무조건 10초를 기다리는 것인 반면

driver.implicitly_wait(10)의 경우, 페이지가 2초만에 로딩된다면, 10초를 기다리지않고 바로 다음 코드로 넘어간다. (즉 8초를 세이브)