5. 待機

最近のWebアプリケーションのほとんどはAJAX技術を使用しています。ブラウザによってページが読み込まれると、そのページ内の要素が異なる時間間隔で読み込まれることがあります。これにより、要素を見つけるkとが難しくなります。要素がDOMにまだ存在しない場合、locate関数は ElementNotVisibleException 例外を発生させます。Waitsを使用して、この問題を解決できます。待つことは、実行されるアクションの間にある程度の余裕を提供します。ほとんどの場合、要素または要素とのその他の操作が検索されます。

Selenium Webdriverは暗黙的と明示的の2種類の待機を提供します。WebDriverを明示的に待機させると、WebDriverは特定の条件が発生するのを待ってからさらに処理を進めます。暗黙的な待機により、WebDriverは、要素の場所を特定しようとすると、一定時間DOMをポーリングします。

5.1. 明示的な待機

明示的待機とは、特定の条件が発生するのを待ってからコードを進めるコードです。これの最悪の場合は、time.sleep()であり、条件を待機する正確な時間に設定します。必要な時間だけ待つコードを書くのに役立つ便利なメソッドがいくつか用意されています。WebDriverWaitとExpectedConditionを組み合わせることで、これを実現できます。

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()

これは、TimeoutExceptionをスローする前に最大10秒間待機するか、要素が0〜10秒で返すことがわかった場合に待機します。WebDriverWaitは、デフォルトで正常に返されるまで500ミリ秒ごとにExpectedConditionを呼び出します。成功した戻り値はExpectedCondition型です。ブール型の場合はtrue、それ以外のExpectedCondition型の場合はnull戻り値です。

期待される条件

Webブラウザを自動化する際に頻繁に発生する一般的な条件がいくつかあります。以下に、それぞれの実装を示します。Selenium Pythonバインディングにはconvienenceメソッドがいくつか用意されていますので、expected_conditionクラスを自分でコーディングしたり、独自のユーティリティパッケージを作成したりする必要はありません。

  • 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
from selenium.webdriver.support import expected_conditions as EC

wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.ID, 'someid')))

expected_conditionsモジュールには、WebDriverWaitで使用する一連の定義済み条件が含まれています。

待機条件をカスタマイズ

以前の簡易メソッドが要件に合致しない場合でも、カスタム待機条件を作成することができます。条件が一致しない場合に False を返す __call__ メソッドを持つクラスを使用してカスタム待機条件を作成できます。

class element_has_css_class(object):
  """An expectation for checking that an element has a particular css class.

  locator - used to find the element
  returns the WebElement once it has the particular css class
  """
  def __init__(self, locator, css_class):
    self.locator = locator
    self.css_class = css_class

  def __call__(self, driver):
    element = driver.find_element(*self.locator)   # Finding the referenced element
    if self.css_class in element.get_attribute("class"):
        return element
    else:
        return False

# Wait until an element with id='myNewInput' has class 'myCSSClass'
wait = WebDriverWait(driver, 10)
element = wait.until(element_has_css_class((By.ID, 'myNewInput'), "myCSSClass"))

5.2. 暗黙の待機

暗黙の待機はすぐに利用できない要素(または複数要素)を見つけようとする時、WebDriverにDOMを一定時間ポーリングするように指示します。デフォルトの設定は0です。一度設定されると、暗黙の待機がWebDriverオブジェクトの有効期間に設定されます。

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")