Python Selenium Explicit Waits 사용하기

록으327·2020년 2월 2일
2

Python

목록 보기
1/1

사용하는 이유

  • AJAX를 사용해 동적으로 변화하는 html페이지의 경우 web element가 DOM로 나타나기까진 시간이 걸릴때가 있다
  • 그 사이에 Selenium이 해당 element를 참조하려고 하면 ElementNotVisibleExceptionNoSuchElementException 에러가 발생할 때가 있다.
  • 이를 방지하기 위해 Selenium에서는 implicit 와 explicite wait 라는 두 가지 방법으로 element가 로딩될 때 까지 기다리게 할 수 있다.
  • 그 중 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
    
    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()

공식 홈페이지에 올라와 있는 예제이다. 한 번 살펴보자

WebDriverWait

    WebDriverWait(driver, 10)

WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) 객체를 생성한다.

  1. driver : 사용할 webdriver 객체를 전달한다
  2. timeout : 최대로 대기할 시간이며 단위는 초이다
  3. poll_frequency : 로딩이 완료될때까지 기다리는 동안 기다리는 element를 일정 시간 간격마다 호출해보게 되는데, 이때 얼마만큼의 시간 간격마다 호출할 것인지를 결정한다. 기본 값은 0.5초이다
  4. ignored_exceptions : 일정 간격마다 element를 호출하는동안 발생하는 Exception 중 무시할 것을 지정할 수 있다. 기본값으로는 NoSuchElementException만 무시한다. iterable한 형식으로 무시할 Exception들을 전달해주면 된다.

until

    .until(...)

WebDriverWait객체에는 두 가지 메소드가 있다.

  1. until(method, message='') : method를 실행해서 False가 아닐 때 까지 기다리게 된다. 공식 API 페이지에 예제가 나와있다.
        until(lambda x: x.find_element_by_id(“someId”))
람다식을 사용하여 *someId* 라는 id를 가진 element를 찾아 False가 아닌 값을 반환할 때 까지 기다리게 된다.
  1. until_not(method, message='') : method를 실행해서 Return값이 **False가 나오지 않을 때 까지** 기다리게 된다. 역시 공식 API 페이지에 예제가 나와있다.

    until_not(lambda x: x.find_element_by_id(“someId”).is_displayed())

    find_element_by_id(“someId”).is_displayed()**False가 될때 까지,** 기다리게 된다. False값을 받아야 하기에 False값을 반환하는 is_displayed()와 같은 메소드를 사용해야 한다.

둘 다 message인자를 통해 error message를 custom 할 수 있다.

until(
    expected_conditions.element_to_be_clickable(click),
    message='My custom message.',
)


>>> selenium.common.exceptions.TimeoutException: Message: My custom message.

Expected Conditions

Selenium은 until과 until_not에 condition으로 사용할 method중 빈번하게 쓰이는 것들을 미리 정의하여 제공하고 있다.

    from selenium.webdriver.support import expected_conditions as EC

expected_conditions 모듈을 import하여 사용할 수 있으며 그 목록은 다음과 같다

  • title_is
  • title_contains
  • presence_of_element_located
  • visibility_of_element_located
  • visibility_of
  • presence_of_all_elements_located
  • text_to_be_present_in_element
  • text_to_be_present_in_element_value
  • frame_to_be_available_and_switch_to_it
  • invisibility_of_element_located
  • element_to_be_clickable
  • staleness_of
  • element_to_be_selected
  • element_located_to_be_selected
  • element_selection_state_to_be
  • element_located_selection_state_to_be
  • alert_is_present

Locate elements By

HTML내에서 어떤 Attribute를 가지고 element를 찾을것인지 정의할 때 사용 할 수 있다

예를들어 아래 두 줄의 코드는 둘 다 같은 결과를 반환한다

    driver.find_element(By.XPATH, '//button[text()="Some text"]')
    driver.find_element_by_xpath('//button[text()="Some text"]')

By 모듈을 import하여 사용할 수 있으며, 정의된 locator들은 다음과 같다

    from selenium.webdriver.common import By

CLASS_NAME = 'class name'

CSS_SELECTOR = 'css selector'

ID = 'id'

LINK_TEXT = 'link text'

NAME = 'name'

PARTIAL_LINK_TEXT = 'partial link text'

TAG_NAME = 'tag name'

XPATH = 'xpath'

이제 위의 예제를 다시 확인해보자

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

목록에 따르면 presence_of_element_located는 element가 DOM에 존재하는지 확인한다. 주의할점은 이는 꼭 브라우저 상에 element가 보이지 않아도 DOM상에 존재 하기만 하면 해당 WebElement객체를 return한다

위 코드는 id attribute의 값이 "myDynamicElement"인 element를 찾아서, 해당 element가 DOM상에 있는것이 확인하게 된다

결론

Selenium의 Explicit Wait에서는 특정한 attribute의 값특정한 Condition을 조합하여 여러가지 상황에 대응할 수 있다. 잘 조합하여 유용하게 써 보자

profile
log327

0개의 댓글