目次
概要
最近のWebサイト(SPAやAjax使用サイト)では、ページを開いた直後にはまだ要素が存在せず、少し遅れて表示されることがよくあります。
Seleniumでエラーを出さずにこれらを操作するためには、要素が出現するまで適切にプログラムを一時停止させる「待機処理」が不可欠です。ここでは「暗黙的待機」と「明示的待機」の2つの手法を解説します。
仕様(入出力)
- 暗黙的待機 (
implicitly_wait):- 入力: 待機する最大秒数
- 効果: ドライバの寿命全体に設定が適用され、要素が見つからない場合に指定時間までポーリング(再確認)し続ける。
- 明示的待機 (
WebDriverWait):- 入力: ドライバ、最大秒数、終了条件(EC)
- 効果: 特定の条件(要素が見えた、クリック可能になった等)が満たされるまで、その場だけで待機する。
基本の使い方
ドライバに「見つからなかったら最大○秒待ってね」と一律で指示する、最も手軽な「暗黙的待機」の設定です。
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
# 暗黙的待機を設定 (最大5秒)
# 以降、find_element実行時に要素がなければ5秒間探し続けます
driver.implicitly_wait(5)
try:
driver.get("https://example.com")
# すぐに見つからなくても、5秒以内に出現すれば取得できます
element = driver.find_element(By.TAG_NAME, "h1")
print(element.text)
finally:
driver.quit()
コード全文
より柔軟で、実務で推奨される「明示的待機 (WebDriverWait)」を使用した実装例です。
「要素が存在するか」だけでなく、「表示されているか(可視性)」を条件に指定して待機します。
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
def wait_for_element_demo():
"""
WebDriverWaitを使用して、特定の要素が表示されるまで待機するデモ関数。
"""
driver = webdriver.Chrome()
# 待機時間の定義(最大10秒)
wait = WebDriverWait(driver, 10)
try:
# 遅延ロードのテストサイト等を開く想定
driver.get("https://morinokabu.com")
print("要素の出現を待機しています...")
# 明示的待機の実行
# until(条件) : 条件がTrueになるか、Web要素を返すまで待機
# EC.visibility_of_element_located : 要素がDOMにあり、かつサイズが0以上で表示されていること
target_element = wait.until(
EC.visibility_of_element_located((By.TAG_NAME, "h1"))
)
# 待機を抜けた=要素が表示された状態
print(f"要素を取得しました: {target_element.text}")
except TimeoutException:
print("指定時間内に要素が表示されませんでした(タイムアウト)。")
except Exception as e:
print(f"予期せぬエラー: {e}")
finally:
driver.quit()
if __name__ == "__main__":
wait_for_element_demo()
カスタムポイント
2つの待機メソッドの違い
| メソッド | 書き方 | 特徴・用途 |
| implicitly_wait | driver.implicitly_wait(秒) | 設定型。一度書けば以降全ての find_element に適用される。「とりあえず全部待ちたい」簡単なスクリプト向け。 |
| WebDriverWait | WebDriverWait(driver, 秒).until(...) | 都度実行型。特定の要素に対して「表示されたら」「クリック可能なら」など詳細な条件で待てる。安定性が高く、実務ではこちらが推奨される。 |
よく使う終了条件 (Expected Conditions)
from selenium.webdriver.support import expected_conditions as EC として使用します。
EC.presence_of_element_located((By.ID, "id"))- HTML内に要素が存在すればOK(表示されていなくてもOK)。
EC.visibility_of_element_located((By.ID, "id"))- 要素が存在し、かつ画面に表示されている(高さ・幅が0より大きい)。
EC.element_to_be_clickable((By.ID, "id"))- 要素が表示されており、かつクリック可能(無効化されていない)。
注意点
- 併用禁止
implicitly_waitとWebDriverWaitを混ぜて使用しないでください。- 予期せぬ長い待機時間が発生したり、動作が不安定になったりする原因になります。どちらか一方(基本は
WebDriverWait)に統一しましょう。
- タプルの二重括弧
ECのメソッドに渡す引数は(By.ID, "name")という1つのタプルである必要があります。EC.presence_of_element_located(By.ID, "name")ではなく、EC.presence_of_element_located((By.ID, "name"))と二重括弧になる点に注意してください。
- タイムアウト例外
- 指定時間内に条件が満たされない場合、
TimeoutExceptionが発生します。必ずtry-exceptで捕捉して、適切なエラー処理(リトライやログ出力)を行ってください。
- 指定時間内に条件が満たされない場合、
応用
「ボタンがクリックできるようになるまで待ってから、クリックする」という、最も安全な操作パターンの実装です。
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
def safe_click(driver, locator, timeout=10):
"""
要素がクリック可能になるのを待ってからクリックするヘルパー関数
"""
try:
element = WebDriverWait(driver, timeout).until(
EC.element_to_be_clickable(locator)
)
element.click()
print("クリック成功")
except Exception:
print("クリックできませんでした")
# 使用例
if __name__ == "__main__":
driver = webdriver.Chrome()
driver.get("https://example.com")
# ID="submit-btn" のボタンを安全にクリック
safe_click(driver, (By.ID, "submit-btn"))
driver.quit()
まとめ
スクレイピングや自動テストの不安定さ(Flaky)の多くは、この「待機処理」の不備が原因です。
手軽な implicitly_wait も便利ですが、確実な動作のためには WebDriverWait と ExpectedConditions を使いこなし、「何の状態を待つのか」を明確に記述する癖をつけましょう。
