Selenium待機処理 完全マスター【Claude Code生成スクリプトでWebDriverWaitを最強化・指数バックオフ付き実例】

スポンサーリンク

こんにちは、Heywaです。

PythonとSeleniumを使ったブラウザ自動化において、最も頭を悩ませる問題の一つが「要素の読み込み待ち」です。スクリプトが早すぎて要素が見つからずエラーになる、かといって長めに待つと全体の処理時間が間延びしてしまう…。

特に最近のWebサイトはJavaScriptで非同期にコンテンツを読み込むSPA(Single Page Application)が主流のため、この「待機処理」をどう設計するかが、自動化システムの安定性を左右する最大の鍵となります。

今回は、Seleniumの待機処理の決定版であるWebDriverWait(明示的待機)について、Claude Codeで生成した実用的なスクリプト実例とともに完全マスターを目指します。NoSuchElementException に悩まされている方は必見です。

スポンサーリンク

Seleniumの3つの待機処理:なぜWebDriverWaitなのか?

Seleniumで要素の読み込みを待つ方法には、大きく分けて3つのアプローチがあります。システム思考的に、それぞれのメリット・デメリットを整理してみましょう。

待機方法 特徴 メリット デメリット
time.sleep() 指定した秒数だけ無条件に処理を停止する コードがシンプルで直感的 読み込みが早くても指定秒数待つため非効率。遅いとエラーになる。
implicitly_wait() 要素が見つかるまで最大指定秒数待つ(暗黙的待機) 一度設定すれば全体に適用される 複雑な条件(クリック可能になるまで等)には対応できない。
WebDriverWait 特定の条件を満たすまで最大指定秒数待つ(明示的待機) 条件が満たされた瞬間に次へ進むため最速。柔軟性が高い。 コードの記述量が少し増える。

結論から言うと、実運用に耐えうる堅牢なスクリプトを書くなら、WebDriverWait(明示的待機)一択です。time.sleep() はデバッグ時のみの使用に留め、本番環境では絶対に避けるべきです。

WebDriverWaitの基本と NoSuchElementException 対策

NoSuchElementException は、「スクリプトが要素を探しに行ったタイミングで、まだDOM上にその要素が存在しなかった」場合に発生します。これを防ぐための基本形が以下です。

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# 最大10秒間待機するWebDriverWaitオブジェクトを作成
wait = WebDriverWait(driver, 10)

# IDが 'submit-btn' の要素がDOM上に現れるまで待機
element = wait.until(EC.presence_of_element_located((By.ID, 'submit-btn')))

このコードの素晴らしい点は、「要素が1秒で現れれば1秒で次の処理に進む」ということです。無駄な待ち時間が発生しません。

よく使う expected_conditions (EC) カタログ

WebDriverWaitの真骨頂は、expected_conditions(EC)と組み合わせることで、様々な「状態」を待機できる点にあります。私がよく使う条件をまとめました。

  • EC.presence_of_element_located: 要素がDOM上に存在するまで待つ(見えていなくてもOK)
  • EC.visibility_of_element_located: 要素が画面上に表示されるまで待つ(高さと幅が0より大きい)
  • EC.element_to_be_clickable: 要素が表示されており、かつクリック可能になるまで待つ(ボタン操作前に必須)
  • EC.text_to_be_present_in_element: 特定の要素内に、指定したテキストが含まれるまで待つ(ローディング完了の判定などに便利)

Claude Codeで生成:指数バックオフ付き最強待機スクリプト

ここからは実践編です。単にWebDriverWaitを使うだけでなく、ネットワークの瞬断やサーバーの一時的な高負荷にも耐えられるよう、「指数バックオフ(Exponential Backoff)を伴うリトライ処理」を組み込んだ最強の待機関数を作ります。

ターミナルでClaude Codeを起動し、以下のように指示を出して生成させたコードをベースにしています。

「PythonとSeleniumで、指定した要素がクリック可能になるまで待機し、クリックする関数を書いて。WebDriverWaitを使用し、TimeoutExceptionが発生した場合は指数バックオフ(1秒、2秒、4秒…)で最大3回リトライする堅牢な設計にして。」

import time
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, ElementClickInterceptedException

def click_with_retry(driver, by_locator, max_retries=3, base_timeout=5):
    """
    指数バックオフを用いた堅牢なクリック処理関数
    
    :param driver: WebDriverインスタンス
    :param by_locator: (By.ID, 'element-id') のようなタプル
    :param max_retries: 最大リトライ回数
    :param base_timeout: 1回あたりの基本待機時間(秒)
    """
    for attempt in range(max_retries):
        try:
            # 試行回数に応じてタイムアウト時間を少しずつ延ばすのも有効
            current_timeout = base_timeout + attempt
            wait = WebDriverWait(driver, current_timeout)
            
            print(f"要素のクリックを試行中... ({attempt + 1}/{max_retries})")
            
            # 要素がクリック可能になるまで待機
            element = wait.until(EC.element_to_be_clickable(by_locator))
            
            # クリック実行
            element.click()
            print("クリックに成功しました。")
            return True
            
        except TimeoutException:
            print(f"TimeoutException: 要素が時間内にクリック可能になりませんでした。")
        except ElementClickInterceptedException:
            print(f"ElementClickInterceptedException: 別の要素が重なっています。")
            # 重なっている要素を消すためのJavaScript実行などをここに挟むとさらに強力
            
        # 最後の試行で失敗した場合は例外を投げる
        if attempt == max_retries - 1:
            raise Exception(f"最大リトライ回数({max_retries})に達しました。対象: {by_locator}")
            
        # 指数バックオフによる待機(1秒 -> 2秒 -> 4秒...)
        sleep_time = 2 ** attempt
        print(f"{sleep_time}秒待機してからリトライします...")
        time.sleep(sleep_time)

# 使用例
# click_with_retry(driver, (By.ID, 'login-button'))

まとめ:待機処理を制する者が自動化を制す

Seleniumを使った自動化スクリプトが「たまに落ちる」原因の9割は、この待機処理の甘さにあります。

time.sleep() の誘惑を断ち切り、WebDriverWait(明示的待機)適切な例外処理(リトライ)を組み合わせることで、スクリプトの安定性は劇的に向上します。私のボートレース予測データ収集システムが2年間無停止で動いているのも、この設計のおかげです。

Claude Codeを使えば、このような少し複雑なロジックも一瞬で生成してくれます。皆さんもぜひ、この「最強の待機関数」を自分のプロジェクトに組み込んで、ストレスフリーな自動化ライフを手に入れてください。

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