Seleniumを使っている時のあるある、”画面上に要素が表示されるまで”とか”入力できるようになるまで”待機する処理をまとめてみました
具体的にはWebDriverWaitとexpected_conditionsの組み合わせになるわけですがexpected_conditionsで指定できる条件が多数ありますが一通り確認してきました
WebDriverWaitについて
指定した条件を満たす(until)もしくは満たさなくなる(not_until)まで待機する便利なモジュールです
Seleniumでブラウザ操作をする上で画面遷移の完了を待つシーンは多く、単純に”sleepでxx秒待つ”処理にしてしまう長過ぎると無駄が多く、短過ぎるとエラーになりがちな雑なプログラムになってしまうのではこのWebDriverWaitは必須レベル
ただし、経験上WebDriverWaitだけではうまくいかない場合があり、最後に0.5秒ほどsleepしてあげると処理が安定する気がします
基本的なパターンはコチラ
WebDriverWait(webdriver, タイムアウトする上限秒数).until(expected_conditionsで設定する上限)
実際にサンプルソースにするとこんな感じです
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
from selenium.common.exceptions import TimeoutException, NoSuchElementException
driver = webdriver.Chrome()
driver.get('https://javeo.jp/practice_scraping/')
try:
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, '#hoge')))
print('条件を満たしました')
except TimeoutException:
print('タイムアウトしました')
except NoSuchElementException:
print('要素が見つかりませんでした')
except Exception:
print('予期せぬエラーが発生しました')
driver.quit()
expected_conditionsについて
WebDriverWaitとセットで使うのがこのexpected_conditions
結局のところexpected_conditionsが肝心の条件部分で、WebDriverWaitはこの条件がエラーにならなくなるまで待つだけの単純仕様
ただこのexpected_conditionsは良くも悪くも指定できる条件が多く、使いこなすには事前把握が望ましいってことでまとめてみました
expected_conditionsのオススメ関数と全関数
“オススメ”は私が個人的によく使う・使えそうだと思うものを、”分類別の全関数”ではある程度グループ分けした関数を全て目次のようにしています※クリックすすれば下部の説明箇所へ飛びます
調べて気づきましたが思ったより多くの関数があって利用シーンが謎なものもチラホラ・・
オススメの条件はできれば”Webelementで指定できる”、”指定方法で別関数を含めた使い方ができる”ことに重きを置いています
- オススメ
- 分類別の全関数
関数 | 条件 |
---|---|
visibility_of | 画面上に見えているか |
presence_of_element_located | DOM上に存在しているか |
element_selection_state_to_be | 選択されている(もしくはされていない)か |
element_to_be_clickable | 利用できる状態か |
text_to_be_present_in_element_attribute | 指定した属性の値と一致しているか |
title_contains | タイトルが指定の文字と部分一致しているか |
分類 | 返値の型 | |
---|---|---|
DOMで判定する ※画面上に見えているかは加味しない | ||
presence_of_element_located(locator: Tuple[str, str]) | WebElement | |
presence_of_all_elements_located(locator: Tuple[str, str]) | WebElement | |
画面上に見えているかで判定する | ||
visibility_of(element: WebElement) | WebElement | |
visibility_of_element_located(locator: Tuple[str, str]) | WebElement | |
visibility_of_all_elements_located(locator: Tuple[str, str]) | List | |
visibility_of_any_elements_located(locator: Tuple[str, str]) | List | |
invisibility_of_element(element: Union[WebElement, Tuple[str, str]]) | bool | |
invisibility_of_element_located(locator: Union[WebElement, Tuple[str, str]]) | bool | |
elementの状態で判定する | ||
element_attribute_to_include(locator: Tuple[str, str], attribute_: str) | bool | |
element_located_selection_state_to_be(locator: Tuple[str, str], is_selected: bool) | bool | |
element_located_to_be_selected(locator: Tuple[str, str]) | bool | |
element_selection_state_to_be(element: WebElement, is_selected: bool) | bool | |
element_to_be_clickable(mark: Union[WebElement, Tuple[str, str]]) | WebElement | |
element_to_be_selected(element: WebElement) | bool | |
文字や要素の値で判定する | ||
text_to_be_present_in_element(locator: Tuple[str, str], text_: str) | bool | |
text_to_be_present_in_element_attribute(locator: Tuple[str, str], attribute_: str, text_: str) | bool | |
text_to_be_present_in_element_value(locator: Tuple[str, str], text_: str) | bool | |
ページタイトルで判定する | ||
title_contains(title: str) | bool | |
title_is(title: str) | bool | |
ページURLで判定する | ||
url_changes(url: str) | bool | |
url_contains(url: str) | bool | |
url_matches(pattern: str) | bool | |
url_to_be(url: str) | bool | |
ブラウザのウィンドウで判定する | ||
number_of_windows_to_be(num_windows: int) | bool | |
new_window_is_opened(current_handles: List[str]) | bool | |
frame要素で判定する | ||
frame_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str]) | bool | |
staleness_of(element: WebElement) | bool | |
アラートポップアップで判定する | ||
alert_is_present() | Alert | |
複合条件にする | ||
all_of(*expected_conditions: Callable[[D], Union[T, Literal[False]]]) | List | |
any_of(*expected_conditions: Callable[[D], T]) | List | |
none_of(*expected_conditions: Callable[[D], Any]) | bool |
presence_of_element_located(locator: Tuple[str, str])
引数のlocatorがDOMに存在すしていれば返り値は該当したWebElementを返す(DOMなので画面上に見えるかどうかは問わない)
引数のlocatorがDOMに存在していなければ返り値はエラー(NoSuchElementException)になる
presence_of_all_elements_located(locator: Tuple[str, str])
引数のlocatorがDOMに存在すしていれば返り値は該当した全てのWebElementを返す(DOMなので画面上に見えるかどうかは問わない)
引数のlocatorがDOMに存在していなければ返り値はエラー(NoSuchElementException)になる
visibility_of(element: WebElement)
引数のelementが画面上に見えていれば返り値は該当したWebElementを返す
引数のelementが存在しなければ返り値はエラー(NoSuchElementException)になる
存在していても画面上に見えていなくても返り値はエラー(TimeoutException)になる
visibility_of_element_located(locator: Tuple[str, str])
引数のlocatorが画面上に見えていれば返り値は該当したWebElementを返す
引数のlocatorが存在しなければ返り値はエラー(NoSuchElementException)に、存在していても画面上に見えていなくても返り値はエラー(TimeoutException)になる
visibility_of_all_elements_located(locator: Tuple[str, str])
引数のlocatorが全て画面上に見えていれば返り値は該当したWebElementを返す
引数のDOM上に存在しないか1つでも非表示になっていれば返り値はエラー(TimeoutException)になる
visibility_of_any_elements_located(locator: Tuple[str, str])
引数のlocatorが画面上に見えていれば返り値は該当したWebElementを返す
引数のlocatorがDOM上に存在しないか1つでも非表示になっていれば返り値はエラー(TimeoutException)になる
invisibility_of_element_located(locator: Union[WebElement, Tuple[str, str]])
引数のelementがDOM上に存在して画面上に見えていなければ返り値は該当したWebElementを返す
引数のelementがDOM上に存在していなければ返り値はTrueを返す
引数のelementがDOM上に存在して画面上に見えていれば返り値はエラー(TimeoutException)になる
※elementはWebElementとlocatorのどちらでもOK
invisibility_of_element(element: Union[WebElement, Tuple[str, str]])
実はinvisibility_of_element_locatedのシノニム
見ての通り実はinvisibility_of_element_locatedをそのまま返してるだけ
element_attribute_to_include(locator: Tuple[str, str], attribute_: str)
引数のlocatorがDOM上に存在し、そのタグの中に引数のattribute_属性があれば返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
element_located_selection_state_to_be(locator: Tuple[str, str], is_selected: bool)
引数のlocatorがDOM上に存在し、その要素が選択されているかどうかが引数のis_selectedと一致していれば返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
※チェックボックスやラジオボタンではない場合、そもそも選択の概念がないのでis_selectedはFalseになる
element_located_to_be_selected(locator: Tuple[str, str])
引数のlocatorが選択されている状態であれば返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
element_selection_state_to_be(element: WebElement, is_selected: bool)
引数のelementがの選択状態が引数のis_selectedと一致していれば返り値はTrueを返す
引数のelementが存在しなければ返り値はエラー(NoSuchElementException)に、存在していても選択状態が引数のis_selectedと一致していないと返り値はエラー(TimeoutException)になる
element_to_be_clickable(mark: Union[WebElement, Tuple[str, str]])
引数のmarkが利用できる状態になっていれば返り値は該当したWebElementを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
※markはWebElementとlocatorのどちらでもOK
element_to_be_selected(element: WebElement)
引数のelementが選択状態になっていれば返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
text_to_be_present_in_element(locator: Tuple[str, str], text_: str)
引数のtext_が引数のlocatorのtextに部分一致していると返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
text_to_be_present_in_element_value(locator: Tuple[str, str], text_: str)
引数のtext_が引数のlocatorのvalue属性に部分一致していると返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
text_to_be_present_in_element_attribute(locator: Tuple[str, str], attribute_: str, text_: str)
引数のtext_が引数のlocatorのattribute_属性に部分一致していると返り値はTrueを返す
それ以外の場合の返り値はエラー(TimeoutException)になる
つまり・・・
- text_to_be_present_in_element=text_to_be_present_in_element_attribute(‘innerText’)
- text_to_be_present_in_element_value=text_to_be_present_in_element_attribute(‘value’)
title_is(title: str)
ページのtitleタグが引数のtitleに完全一致していれば返り値はTrueを返す
title_contains(title: str)
ページのtitleタグが引数のtitleに部分一致していれば返り値はTrueを返す
url_contains(url: str)
ページのurlが引数のurlに部分一致していれば返り値はTrueを返す
url_matches(pattern: str)
ページのurlが引数のpatternに正規表現でマッチしていれば返り値はTrueを返す
url_to_be(url: str)
ページのurlが引数のurlに完全一致していれば返り値はTrueを返す
url_changes(url: str)
ページのurlが引数のurlに不一致であれば返り値はTrueを返す
number_of_windows_to_be(num_windows: int)
ウィンドウの数が引数のnum_windowsと一致していれば返り値はTrueを返す
new_window_is_opened(current_handles: List[str])
これは正直使い道が謎・・・
ウィンドウの数が増えたら?っぽいですがどうやって開くのか・・・
どちらにしても使い道は無いかと
frame_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str])
引数のlocatorのframeに遷移できれば返り値はTrueを返す
staleness_of(element: WebElement)
引数のelementにアタッチできるか、らしいのですが結局is_enabled()だけ
alert_is_present()
アラートがあればそのアラートに遷移させる
any_of(*expected_conditions: Callable[[D], T])
指定したexpected_conditionsが一つでもTrueになった判定
all_of(*expected_conditions: Callable[[D], Union[T, Literal[False]]])
指定したexpected_conditionsが全てTrueになった判定
none_of(*expected_conditions: Callable[[D], Any])
指定したexpected_conditionsが全てTrueにならなかった判定
あとがき
expected_conditionsは調べてみると知らないだけで多くの関数がありました
presence_of_element_locatedやvisibility_of_element_locatedは有名ですがtext_to_be_present_in_elementやelement_to_be_clickableも有用そうで今後活用してみたい!
引数はTuple型のlocatorとWebElement型のelement、どちらでも対応できるパターンがありますがどうせなら全部どちらにも対応できるパターンにしてほしい・・・
コメント