Python | Web / API:WebDriverWait

Python Python
スポンサーリンク

概要(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()
Python

visibility_of_element_locatedは「DOMに存在し、かつ表示されている」状態を保証します。待機条件は目的に合わせて選ぶのがコツです。

クリックは「クリック可能」を待ってから

btn = WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.CSS_SELECTOR, "button[type=submit]"))
)
btn.click()
Python

element_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")))          # クリック可能
Python

presenceは「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")))  # ローディング消失
Python

iframeは「スイッチしてから操作」が必須。ローディングの消失待ちは動的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")))
Python

poll_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ページで「落ちない・速い・確実」な自動化が短いコードで書けます。

タイトルとURLをコピーしました