Seleniumでブラウザを自動操作していると、「要素がまだ読み込まれていなくてエラーになる」という場面によく出会います
そんなとき time.sleep() で適当に待つ人も多いですが、これだと待ちすぎたり待ち足りなかったりで安定しないんですよね
結論から言うと、Seleniumの待機は time.sleep ではなく WebDriverWait と expected_conditions の組み合わせが確実です
「条件が満たされたら、その瞬間に次へ進む」という待ち方ができるので、無駄もなければ取りこぼしもないんです
この記事では WebDriverWait の基本の書き方から、条件を指定する expected_conditions の一覧、さらに各条件がSeleniumの内部でどう動いているかまで、じっくり解説していきます
後半は全条件のリファレンスになっているので、「あの条件どう書くんだっけ」というときの辞書としても使ってくださいね
WebDriverWait について
WebDriverWait は、指定した条件を満たすまで待機してくれる便利なモジュールです
Seleniumでブラウザを操作するとき、特定の条件が整うまで待ちたいシーンってすごく多いんですよね
そこで time.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('条件を満たせませんでした')
driver.quit()import の書き方は expected_conditions を EC という別名で読み込むのが定番です、Selenium 4 でもこの書き方で問題なく動きます
Pythonでは WebDriverWait と expected_conditions は今も標準・現役で、基本パターンはずっと変わっていません、安心して使えますよ
なぜ time.sleep より良いのか
そもそも time.sleep() は「指定した秒数、問答無用で止まる」だけの処理です
import time
time.sleep(5) # 5秒待つネットワークが遅い日は5秒でも足りず、速い日は0.5秒で表示されているのに5秒待つ、みたいな無駄が出るんですね
一方の WebDriverWait は、条件が満たされた瞬間に次へ進むので、無駄な待ち時間がありません
とはいえ time.sleep も、デバッグ中にちょっと動きを止めて確認したいときなんかには便利なので、完全に使わないわけではないです
「本番の待機には WebDriverWait、確認用にたまに sleep」くらいの距離感がちょうどいいと思います
timeout と poll_frequency
WebDriverWait には、タイムアウトまでの秒数のほかに、チェックの間隔も指定できます
wait = WebDriverWait(driver, timeout=10, poll_frequency=0.5)driver: WebDriverのインスタンスtimeout: 最大待機秒数poll_frequency: チェックする間隔(秒)、省略すると0.5秒
つまり「10秒間、0.5秒ごとに条件をチェックする」という設定です
timeout には 10 のような整数秒を渡すのが基本で、Pythonではこの数値指定で問題なく動きます、まずは整数秒で覚えてしまって大丈夫です
ちなみにSelenium 4 以降は、待機時間を datetime.timedelta のような「期間オブジェクト」で扱う流れがあります(Java版などはすでに Duration 指定が中心です)
Python版は今のところ整数秒でも普通に使えるので、ここは「将来的にはそういう流れもある」くらいの認識で十分だと思います
expected_conditions について
WebDriverWait とセットで使うのが、この expected_conditions です
結局のところ expected_conditions が肝心の条件部分で、WebDriverWait はその条件が正常終了 or True になるまで待つだけ、という仕様なんですね
ただこの expected_conditions、良くも悪くも指定できる条件がかなり多くて、使いこなすには事前に把握しておきたいところ、ということでまとめてみました
調べていて気づきましたが、思ったより多くの関数があって、利用シーンが謎なものもチラホラあります
また、expected_conditions の返り値はいろいろありますが、WebDriverWait とセットで使うと、WebDriverWait の仕様上、返り値は正常終了時の値 or エラー(TimeoutException)になります、try-except するときは注意してくださいね
よく使う関数
まずは私が個人的によく使う・使えそうだと思う関数だけをまとめた表です、関数名をクリックすると下のリファレンスに飛べます
| 関数 | 条件 |
|---|---|
| presence_of_element_located | DOM上に存在しているか |
| visibility_of_element_located | 画面上に表示されているか |
| invisibility_of_element_located | 画面上で非表示になっているか |
| element_to_be_clickable | 画面上に表示されてかつ利用できる状態か |
正直、最初はこの4つだけで大半のケースは何とかなります
分類別の全関数一覧
続いて、ある程度グループ分けした全関数を、目次のように並べた表です
| 分類 | 関数 | 返値の型 |
|---|---|---|
| DOMで判定する (画面上に見えているかは加味しない) | presence_of_element_located | WebElement |
| presence_of_all_elements_located | List | |
| 画面上の表示・非表示で判定する | visibility_of | WebElement |
| visibility_of_element_located | WebElement | |
| visibility_of_all_elements_located | List | |
| visibility_of_any_elements_located | List | |
| invisibility_of_element | bool | |
| invisibility_of_element_located | bool | |
| elementの状態で判定する | element_attribute_to_include | bool |
| element_located_selection_state_to_be | bool | |
| element_located_to_be_selected | bool | |
| element_selection_state_to_be | bool | |
| element_to_be_clickable | WebElement | |
| element_to_be_selected | bool | |
| 文字や要素の値で判定する | text_to_be_present_in_element | bool |
| text_to_be_present_in_element_attribute | bool | |
| text_to_be_present_in_element_value | bool | |
| ページタイトルで判定する | title_contains | bool |
| title_is | bool | |
| ページURLで判定する | url_changes | bool |
| url_contains | bool | |
| url_matches | bool | |
| url_to_be | bool | |
| ブラウザのウィンドウで判定する | number_of_windows_to_be | bool |
| new_window_is_opened | bool | |
| frame要素・状態で判定する | frame_to_be_available_and_switch_to_it | bool |
| staleness_of | bool | |
| アラートポップアップで判定する | alert_is_present | Alert |
| 複合条件にする | all_of | List |
| any_of | List | |
| none_of | bool |
では、ここから各関数を1つずつ詳しく見ていきます、内部のソースコードも引用しているので、挙動が気になる人はそちらもどうぞ
presence_of_element_located(locator: Tuple[str, str])
引数の locator が DOM に存在していれば、返り値は該当した WebElementを返します(DOMなので画面上に見えるかどうかは問わない)
内部的には find_element で locator の有無を確認しているだけです
def presence_of_element_located(locator: tuple[str, str]) -> Callable[[WebDriverOrWebElement], WebElement]:
def _predicate(driver: WebDriverOrWebElement):
return driver.find_element(*locator)
return _predicatepresence_of_all_elements_located(locator: Tuple[str, str])
引数の locator が DOM に存在していれば、返り値は該当した全ての WebElement を返します(DOMなので画面上に見えるかどうかは問わない)
待機するだけなら presence_of_element_located と同じですね
def presence_of_all_elements_located(locator: tuple[str, str]) -> Callable[[WebDriverOrWebElement], list[WebElement]]:
def _predicate(driver: WebDriverOrWebElement):
return driver.find_elements(*locator)
return _predicatevisibility_of_element_located(locator: Tuple[str, str])
引数の locator が画面上に見えていれば、返り値は該当した WebElementを返します
実態は locator の有無確認と is_displayed() をしているだけです
def visibility_of_element_located(
locator: tuple[str, str],
) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]:
def _predicate(driver: WebDriverOrWebElement):
try:
return _element_if_visible(driver.find_element(*locator))
except StaleElementReferenceException:
return False
return _predicatedef _element_if_visible(element: WebElement, visibility: bool = True) -> Union[Literal[False], WebElement]:
return element if element.is_displayed() == visibility else Falsevisibility_of(element: WebElement)
引数の element が画面上に見えていれば、返り値は該当した WebElement を返します
引数にした WebElement がそのまま返り値になるので、単純な待機処理としてしか使うことはなさそうですね
def visibility_of(element: WebElement) -> Callable[[Any], Union[Literal[False], WebElement]]:
def _predicate(_):
return _element_if_visible(element)
return _predicatevisibility_of_all_elements_located(locator: Tuple[str, str])
引数の locator が全て画面上に見えていれば、返り値は該当した全ての WebElement を返します
ただし、locator が1つでも DOM 上に存在しないか非表示(hidden)になっていればエラーになる絶妙仕様なので、使うことはあまりなさそうです
def visibility_of_all_elements_located(
locator: tuple[str, str],
) -> Callable[[WebDriverOrWebElement], Union[list[WebElement], Literal[False]]]:
def _predicate(driver: WebDriverOrWebElement):
try:
elements = driver.find_elements(*locator)
for element in elements:
if _element_if_visible(element, visibility=False):
return False
return elements
except StaleElementReferenceException:
return False
return _predicatevisibility_of_any_elements_located(locator: Tuple[str, str])
引数の locator が画面上に見えていれば、返り値は該当した全ての WebElement を返します
こちらは locator が DOM 上に存在しない場合のみエラーになり、1つでも表示されていれば、表示されている WebElement を返してくれます
def visibility_of_any_elements_located(locator: tuple[str, str]) -> Callable[[WebDriverOrWebElement], list[WebElement]]:
def _predicate(driver: WebDriverOrWebElement):
return [element for element in driver.find_elements(*locator) if _element_if_visible(element)]
return _predicateinvisibility_of_element_located(locator: Union[WebElement, Tuple[str, str]])
visibility_of_element_located の逆で、DOM 上に見えてないことを検知してくれます
DOM 上になければ True、DOM 上にあるけど非表示なら対象の WebElement を返してくれます、ローディング画面が消えるのを待つ、みたいなときに便利ですね
def invisibility_of_element_located(
locator: Union[WebElement, tuple[str, str]],
) -> Callable[[WebDriverOrWebElement], Union[WebElement, bool]]:
def _predicate(driver: WebDriverOrWebElement):
try:
target = locator
if not isinstance(target, WebElement):
target = driver.find_element(*target)
return _element_if_visible(target, visibility=False)
except (NoSuchElementException, StaleElementReferenceException):
# In the case of NoSuchElement, returns true because the element is
# not present in DOM. The try block checks if the element is present
# but is invisible.
# In the case of StaleElementReference, returns true because stale
# element reference implies that element is no longer visible.
return True
return _predicateinvisibility_of_element(element: Union[WebElement, Tuple[str, str]])
実は invisibility_of_element_located のシノニム(別名)です
見ての通り、実は locator でも受け付けできて、invisibility_of_element_located をそのまま返しているだけなんですね
def invisibility_of_element(
element: Union[WebElement, tuple[str, str]],
) -> Callable[[WebDriverOrWebElement], Union[WebElement, bool]]:
return invisibility_of_element_located(element)element_attribute_to_include(locator: Tuple[str, str], attribute_: str)
引数の locator が DOM 上に存在し、さらにそのタグの中に引数の attribute_ 属性があるかで照合します(それ以外はエラー)
使い道としては、JavaScriptで要素が追加されるときぐらいですかね
def element_attribute_to_include(locator: tuple[str, str], attribute_: str) -> Callable[[WebDriverOrWebElement], bool]:
def _predicate(driver: WebDriverOrWebElement):
try:
element_attribute = driver.find_element(*locator).get_attribute(attribute_)
return element_attribute is not None
except StaleElementReferenceException:
return False
return _predicateelement_located_selection_state_to_be(locator: Tuple[str, str], is_selected: bool)
引数の locator が DOM 上に存在し、さらにその要素の選択状況と引数の is_selected が合っているかで判定を返してくれます
locator が DOM 上に存在しないときはエラーになります
チェックボックスやラジオボタンではない場合、そもそも選択の概念がないので is_selected() は False になります
def element_located_selection_state_to_be(
locator: tuple[str, str], is_selected: bool
) -> Callable[[WebDriverOrWebElement], bool]:
def _predicate(driver: WebDriverOrWebElement):
try:
element = driver.find_element(*locator)
return element.is_selected() == is_selected
except StaleElementReferenceException:
return False
return _predicateelement_located_to_be_selected(locator: Tuple[str, str])
引数の locator が選択されている状態であるかで照合します
is_selected() はあまり使う機会がないと思うんですよね
def element_located_to_be_selected(locator: tuple[str, str]) -> Callable[[WebDriverOrWebElement], bool]:
def _predicate(driver: WebDriverOrWebElement):
return driver.find_element(*locator).is_selected()
return _predicateelement_to_be_selected(element: WebElement)
element_located_to_be_selected の引数が locator から WebElement になった版です
def element_to_be_selected(element: WebElement) -> Callable[[Any], bool]:
def _predicate(_):
return element.is_selected()
return _predicateelement_selection_state_to_be(element: WebElement, is_selected: bool)
element_to_be_selected で is_selected() == False が選べるようになっただけです
def element_selection_state_to_be(element: WebElement, is_selected: bool) -> Callable[[Any], bool]:
def _predicate(_):
return element.is_selected() == is_selected
return _predicateelement_to_be_clickable(mark: Union[WebElement, Tuple[str, str]])
まず引数が mark(WebElement と locator のどちらでもOK)になっているのに好感が持てます
※全部そうしてほしい
内部的には visibility_of かつ is_enabled() なので、clickable という名前からチェックボックス向けのような印象を受けますが、input タグなどにも有効です(むしろこっちの方が利用頻度が高い)
def element_to_be_clickable(
mark: Union[WebElement, tuple[str, str]],
) -> Callable[[WebDriverOrWebElement], Union[Literal[False], WebElement]]:
# renamed argument to 'mark', to indicate that both locator
# and WebElement args are valid
def _predicate(driver: WebDriverOrWebElement):
target = mark
if not isinstance(target, WebElement): # if given locator instead of WebElement
target = driver.find_element(*target) # grab element at locator
element = visibility_of(target)(driver)
if element and element.is_enabled():
return element
return False
return _predicatetext_to_be_present_in_element(locator: Tuple[str, str], text_: str)
XPATHの [text()=’hoge’] を事前チェックできる感じです
需要がありそうでなさそう、、、で、やっぱりありそうな関数です、「処理が完了しました」のような表示を待つときに便利ですよ
def text_to_be_present_in_element(locator: tuple[str, str], text_: str) -> Callable[[WebDriverOrWebElement], bool]:
def _predicate(driver: WebDriverOrWebElement):
try:
element_text = driver.find_element(*locator).text
return text_ in element_text
except StaleElementReferenceException:
return False
return _predicatetext_to_be_present_in_element_value(locator: Tuple[str, str], text_: str)
text_to_be_present_in_element を text から value 属性に変えてみました、という関数です
もともと微妙な需要だったのに、さらに下がってる気がします
def text_to_be_present_in_element_value(
locator: tuple[str, str], text_: str
) -> Callable[[WebDriverOrWebElement], bool]:
def _predicate(driver: WebDriverOrWebElement):
try:
element_text = driver.find_element(*locator).get_attribute("value")
if element_text is None:
return False
return text_ in element_text
except StaleElementReferenceException:
return False
return _predicatetext_to_be_present_in_element_attribute(locator: Tuple[str, str], attribute_: str, text_: str)
text_to_be_present_in_element_value を、value 以外の属性を選べるようにしてみました
じゃあ text_to_be_present_in_element_value いらない・・・となりますね
def text_to_be_present_in_element_attribute(
locator: tuple[str, str], attribute_: str, text_: str
) -> Callable[[WebDriverOrWebElement], bool]:
def _predicate(driver: WebDriverOrWebElement):
try:
element_text = driver.find_element(*locator).get_attribute(attribute_)
if element_text is None:
return False
return text_ in element_text
except StaleElementReferenceException:
return False
return _predicatetitle_is(title: str)
title との完全一致判定です
title 自体ちょっと使いにくいのに、完全一致はなかなか難しい印象です
def title_is(title: str) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return driver.title == title
return _predicatetitle_contains(title: str)
こちらは title の部分一致判定です
完全一致よりは現実的だけど、やっぱり title で照合はしないと思います
def title_contains(title: str) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return title in driver.title
return _predicateurl_contains(url: str)
url の部分一致で判定します
個人的には待機処理の条件に url はあまり使わないかなと思います、ただ、ボタンを押してページが切り替わるのを待ちたいときには出番がありますね
def url_contains(url: str) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return url in driver.current_url
return _predicateurl_matches(pattern: str)
こちらは url を正規表現で判定します
URLにIDなどが含まれていて完全一致では指定しづらいとき、正規表現で柔軟に待てるのは便利ですね、ちなみに Selenium 4 で整理された比較的新しい条件です
def url_matches(pattern: str) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return re.search(pattern, driver.current_url) is not None
return _predicateurl_to_be(url: str)
url の完全一致で判定します
遷移先のURLがきっちり決まっているときには使えますよ
def url_to_be(url: str) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return url == driver.current_url
return _predicateurl_changes(url: str)
url の不一致で判定します、指定したURLから変わるまで待つ、という条件ですね
クリック後にページが切り替わるのを待つ、みたいなときに自然に使えます、こちらも Selenium 4 系で整理された条件です
def url_changes(url: str) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return url != driver.current_url
return _predicatenumber_of_windows_to_be(num_windows: int)
ウィンドウ(=タブ)の数で照合します
新しいタブが開くのを待ちたいとき以外は、出番が少なめかもしれません
def number_of_windows_to_be(num_windows: int) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return len(driver.window_handles) == num_windows
return _predicatenew_window_is_opened(current_handles: List[str])
新しいウィンドウができるまで待ってくれる、らしいです
number_of_windows_to_be と用途は近いですが、開く前のウィンドウ数を渡しておけば、それより増えたかどうかで判定してくれます
def new_window_is_opened(current_handles: list[str]) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
return len(driver.window_handles) > len(current_handles)
return _predicateframe_to_be_available_and_switch_to_it(locator: Union[Tuple[str, str], str])
指定の frame に移動できるまで待ちます
待機処理としてより、switch_to.frame を安全にする使い方なら需要がありそうです、iframe を操作するときに役立ちますね
def frame_to_be_available_and_switch_to_it(
locator: Union[tuple[str, str], str, WebElement],
) -> Callable[[WebDriver], bool]:
def _predicate(driver: WebDriver):
try:
if isinstance(locator, Iterable) and not isinstance(locator, str):
driver.switch_to.frame(driver.find_element(*locator))
else:
driver.switch_to.frame(locator)
return True
except NoSuchFrameException:
return False
return _predicatestaleness_of(element: WebElement)
なんでこんな名前になったのか、、実態は is_enabled だけです、要素が古くなる(DOMから削除される)のを検知できるので、ページ遷移の確認に便利ですね
def staleness_of(element: WebElement) -> Callable[[Any], bool]:
def _predicate(_):
try:
# Calling any method forces a staleness check
element.is_enabled()
return False
except StaleElementReferenceException:
return True
return _predicatealert_is_present()
アラートに遷移できるかを判定します
frame_to_be_available_and_switch_to_it と同じく、待機処理としてより、switch_to.alert を安全にする使い方なら需要がありそうです
def alert_is_present() -> Callable[[WebDriver], Union[Alert, Literal[False]]]:
def _predicate(driver: WebDriver):
try:
return driver.switch_to.alert
except NoAlertPresentException:
return False
return _predicateany_of(*expected_conditions: Callable[[D], T])
指定した複数の expected_conditions が、1つでも True になればOKという条件です
「成功表示か、エラー表示の、どちらかが出るまで待つ」みたいな分岐に便利です、こちらも Selenium 4 で追加されました
def any_of(*expected_conditions: Callable[[D], T]) -> Callable[[D], Union[Literal[False], T]]:
def any_of_condition(driver: D):
for expected_condition in expected_conditions:
try:
result = expected_condition(driver)
if result:
return result
except WebDriverException:
pass
return False
return any_of_conditionall_of(*expected_conditions: Callable[[D], Union[T, Literal[False]]])
こちらは指定した複数の expected_conditions が、全て True になればOKという条件です
複数の条件をまとめてチェックしたいときに使います、any_of とセットで Selenium 4 で追加されました
def all_of(
*expected_conditions: Callable[[D], Union[T, Literal[False]]],
) -> Callable[[D], Union[list[T], Literal[False]]]:
def all_of_condition(driver: D):
results: list[T] = []
for expected_condition in expected_conditions:
try:
result = expected_condition(driver)
if not result:
return False
results.append(result)
except WebDriverException:
return False
return results
return all_of_conditionnone_of(*expected_conditions: Callable[[D], Any])
こちらは指定した複数の expected_conditions が、1つも True にならなければOKという条件です
「エラー表示が出ないまま処理が進んだか」を確かめたいときなんかに使えます
def none_of(*expected_conditions: Callable[[D], Any]) -> Callable[[D], bool]:
def none_of_condition(driver: D):
for expected_condition in expected_conditions:
try:
result = expected_condition(driver)
if result:
return False
except WebDriverException:
pass
return True
return none_of_conditionexpected_conditions にない条件は lambda で自作できる
ここまで全関数を見てきましたが、「ちょうどいい条件がない」というケースもあります
そんなときは、until に自作の関数(条件)を渡せます
「driver を受け取って、満たされたら値を返す(満たされなければ False を返す)」関数を渡せばいいだけなので、lambda でサクッと書けるんですね
from selenium.webdriver.common.by import By
# 要素のテキストが空でなくなるまで待つ自作条件
element = WebDriverWait(driver, 10).until(
lambda d: d.find_element(By.ID, "status") if d.find_element(By.ID, "status").text != "" else False
)expected_conditions に用意されていない細かい条件で待ちたいときは、この lambda 方式を覚えておくと一気に応用が利きます
そもそも要素の取得自体に迷うときは、Seleniumで要素を取得する find_element の使い方もあわせて読むと、待機とセットでスッキリ書けるようになりますよ
WebDriverWait のよくあるエラーと注意点
TimeoutException が出る
指定した時間内に条件が満たされなかったときに出るエラーです
一番よく見るエラーですね
from selenium.common.exceptions import TimeoutException
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "main"))
)
except TimeoutException:
print("要素が見つかりませんでした")try-except で囲んで、タイムアウト時の処理を書いておくと安心です
原因としては、セレクタが間違っているか、本当に表示まで時間がかかっているかのどちらかが多いです
要素は見つかるのにクリックできない
presence では見つかるのに、いざクリックするとエラーになることがあります
これは要素は存在するけど、まだ表示されていない・操作できない状態だからですね
そういうときは element_to_be_clickable を使うと解決することが多いです
暗黙的な待機と混ぜると危険
ここは2026年の今でも引っかかる人が多いポイントなので、しっかり押さえておきたいところです
Seleniumには WebDriverWait(明示的な待機)とは別に、implicitly_wait() という「暗黙的な待機」もあります
driver.implicitly_wait(10) # 要素が見つかるまで最大10秒待つ(全体に適用)これ自体は楽な仕組みなんですが、WebDriverWait と併用すると、待機時間が予期せず長くなることがあります
これは両方の待機が重なってしまうからです
例えば暗黙的な待機を10秒、明示的な待機を15秒に設定していると、タイムアウトが20秒後に起きる、といった予測しづらい挙動になることがあります
Seleniumの公式ドキュメントでも、暗黙的な待機と明示的な待機は混在させないようにと、はっきり警告されています
個人的には WebDriverWait に統一する派です、条件ごとに細かく待てて、挙動も読みやすいので
こうした自動化スクリプトを実際に動かすときは、ログインや個人情報の扱いなど安全面の配慮も大切です、不安な方は自動化を始める前に知っておきたい安全性の基本もあわせて読んでみてくださいね
あとがき
expected_conditions は、調べてみると知らないだけで多くの関数がありました
presence_of_element_located や visibility_of_element_located は有名ですが、text_to_be_present_in_element や element_to_be_clickable も有用そうで、今後活用してみたいと思います
引数は Tuple 型の locator と WebElement 型の element、どちらでも対応できるパターンがありますが、どうせなら全部どちらにも対応できるパターンにしてほしいところです
ポイントをまとめると、こんな感じです
- 本番の待機は time.sleep ではなく WebDriverWait を使う
- WebDriverWait は「条件が満たされるまで待つ」賢い待機
- 条件は expected_conditions で指定する
- よく使うのは presence / visibility / clickable / invisibility あたり
- 足りない条件は lambda で自作できる
- 暗黙的な待機との併用は避ける
最初は presence_of_element_located と element_to_be_clickable の2つだけ覚えておけば、だいたい何とかなります
実際にPythonでスクレイピングを動かしてみたい方は、Pythonでnetkeibaをスクレイピングしてみた実例もどうぞ、待機処理が実戦でどう効いてくるかイメージしやすいと思います
あなたのSeleniumの自動化が、もっと安定して動くようになればうれしいです



コメント