概要(WebDriverWaitは「準備が整ってから動く」ための安定化の核)
WebDriverWaitは、Seleniumで「要素が見える」「クリック可能」「URLが変わる」などの状態になるまで待ってから次の操作をする仕組みです。固定の待機秒(time.sleep)より速くて安定し、NoSuchElementExceptionやクリック失敗の定番エラーを大幅に減らします。重要ポイントは、待機対象の状態(expected conditions)を正しく選ぶこと、タイムアウトと例外処理、要素の再取得(stale対策)、そして「表示→クリック可能」の二段待機です。
基本の使い方(ここが重要)
最短のWebDriverWait(要素の表示を待つ)
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
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.Chrome(service=Service(ChromeDriverManager().install()))
driver.get("https://example.com/login")
wait = WebDriverWait(driver, 10) # 最大10秒待機
user = wait.until(EC.visibility_of_element_located((By.ID, "username")))
pwd = wait.until(EC.visibility_of_element_located((By.ID, "password")))
user.send_keys("taro"); pwd.send_keys("secret123")
driver.quit()
Pythonvisibility_of_element_locatedは「DOMに存在し、かつ表示されている」状態を保証します。待機条件は目的に合わせて選ぶのがコツです。
クリックは「クリック可能」を待ってから
btn = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type=submit]"))
)
btn.click()
Pythonelement_to_be_clickableは「表示され、重なりがなく、押せる」状態の確認です。表示直後はまだ押せないことがあるため、表示待ちとクリック待ちを分けると安定します。
待機条件の選び方(expected conditionsの実用セット)
要素関連(存在・表示・クリック可能)
wait = WebDriverWait(driver, 10)
present = wait.until(EC.presence_of_element_located((By.ID, "target"))) # 存在のみ
visible = wait.until(EC.visibility_of_element_located((By.ID, "target"))) # 表示状態
clickable = wait.until(EC.element_to_be_clickable((By.ID, "target"))) # クリック可能
Pythonpresenceは「DOMにある」だけで非表示でも成立します。表示が必要ならvisibility、操作が必要ならclickableを選びます。
複数要素・テキスト・URL・タイトル
rows = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.item"))) # 複数
wait.until(EC.text_to_be_present_in_element((By.ID, "status"), "完了")) # テキスト
wait.until(EC.url_contains("/dashboard")) # URL変化
wait.until(EC.title_contains("検索結果")) # タイトル変化
Python画面遷移の検証や処理完了の検出に向いた条件です。「クリック→URL変化」など、操作の次の状態を待つとテストが堅くなります。
フレーム・アラート・不可視の確認
wait.until(EC.frame_to_be_available_and_switch_to_it((By.CSS_SELECTOR, "iframe#payment")))
alert = wait.until(EC.alert_is_present()) # 標準アラートの出現
wait.until(EC.invisibility_of_element_located((By.ID, "loading"))) # ローディング消失
Pythoniframeは「スイッチしてから操作」が必須。ローディングの消失待ちは動的UIで有効です。
タイムアウト・例外・ポーリング(「落ちない」ための細部)
タイムアウトと例外の扱い
from selenium.common.exceptions import TimeoutException
try:
el = WebDriverWait(driver, 8).until(EC.visibility_of_element_located((By.ID, "username")))
except TimeoutException:
print("入力欄が現れない/表示されない(ロケータの再確認・待機条件の見直し)")
Python待機は「最大時間の上限」を設けるのが基本。タイムアウト時はロケータの誤り、条件の過不足、ネットワーク遅延を疑い調整します。
ポーリング間隔と無視する例外の設定
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException
wait = WebDriverWait(driver, 10, poll_frequency=0.2, ignored_exceptions=(NoSuchElementException, StaleElementReferenceException))
el = wait.until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div.item")))
Pythonpoll_frequencyで「何秒おきに再試行するか」を調整。DOM差し替えが頻発するページではStaleを無視して再試行すると安定します。
stale対策(要素の再取得を前提にする)
from selenium.common.exceptions import StaleElementReferenceException
el = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "div.item")))
try:
text = el.text # DOM更新でstaleになることがある
except StaleElementReferenceException:
el = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, "div.item"))) # 取り直す
text = el.text
Python動的更新で古い参照が無効になるのがstale。操作直前に「取り直す」発想が有効です。
実務の型(表示→クリック→遷移→抽出の一連を待機で守る)
ログイン→検索→抽出(明示的待機で全工程を安定化)
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
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.Chrome(service=Service(ChromeDriverManager().install()))
wait = WebDriverWait(driver, 12)
try:
driver.get("https://example.com/login")
wait.until(EC.visibility_of_element_located((By.ID, "username"))).send_keys("taro")
wait.until(EC.visibility_of_element_located((By.ID, "password"))).send_keys("secret")
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type=submit]"))).click()
wait.until(EC.url_contains("/dashboard"))
wait.until(EC.visibility_of_element_located((By.NAME, "q"))).send_keys("selenium 待機");
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.search"))).click()
rows = wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.item")))
for r in rows[:10]:
title = r.find_element(By.CSS_SELECTOR, "h3").text
link = r.find_element(By.CSS_SELECTOR, "a").get_attribute("href")
print(title, link)
finally:
driver.quit()
Python各ステップを対応する状態で待つと「要素がない」「押せない」「遷移しない」類のエラーを潰せます。
ローディング消失→クリック→結果出現の連鎖
wait.until(EC.invisibility_of_element_located((By.CSS_SELECTOR, ".loading")))
wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "button.apply"))).click()
wait.until(EC.visibility_of_element_located((By.ID, "result")))
Python「消えたら押す、押したら出る」――UIの状態遷移を待機でモデル化すると自然に安定します。
よくある落とし穴の回避(暗黙待機・固定sleep・長いXPath)
暗黙的待機(implicitly_wait)の乱用で混乱
暗黙待機は「全取得に自動で待機」をかけますが、明示的待機と併用すると分かりにくく、思わぬ遅延を招きます。基本は「明示的待機(WebDriverWait)」に一本化します。
固定sleepは「遅いか足りない」のどちらかになる
time.sleepでの待機は、ネットワークや端末差で揺れます。状態ベースの待機(EC)へ置き換えると、速くて安定します。
長い絶対XPathはDOM変更に弱い
ロケータはまずID/NAME、次に短いCSS、最後に属性中心の短いXPath。変更耐性のある指定を優先します。
まとめ
WebDriverWaitは、Seleniumを「状態が整ってから確実に操作する」ための中核です。目的に応じた待機条件(presence/visibility/clickable、URLやタイトル、iframeやアラート、不可視)を選び、タイムアウトと例外を丁寧に扱う。ポーリングと例外無視で動的更新に強くし、staleを前提に要素の再取得を取り入れる。固定sleepや暗黙待機より、状態ベースの明示的待機へ。これらを型として体に入れると、初心者でも動的なWebページで「落ちない・速い・確実」な自動化が短いコードで書けます。
