Seleniumは、Webアプリケーションの機能検証やUI操作をプログラムで再現するためのオープンソースフレームワークです。Pythonとの連携が特に直感的で、開発・テスト両サイドから広く採用されています。
主な特徴と利点
- マルチブラウザ対応:Chrome、Firefox、Edgeなど、W3C準拠のWebDriverをサポートするすべてのブラウザで動作
- 明示的な待機制御:静的スリープではなく、要素の状態(表示・有効・クリック可能など)に基づいた柔軟な待機が可能
- ローカル・リモート両対応:ローカル環境だけでなく、Selenium GridやCloudサービス(BrowserStackなど)とも統合可能
- セキュアなコンテキスト操作:iframe切り替え、ウィンドウハンドル管理、アラート処理など、複雑なページ構造にも対応
基本的な実装フロー
以下のコードは、検索エンジンでキーワードを送信し、結果ページへ遷移する一連の操作を示します。WebDriverManagerを用いてドライバの管理を自動化しています。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from webdriver_manager.chrome import ChromeDriverManager
# ドライバの自動設定と起動
service = Service(ChromeDriverManager().install())
driver = webdriver.Chrome(service=service)
wait = WebDriverWait(driver, 15)
try:
# ページ読み込み
driver.get("https://example.com")
# 検索ボックスの待機と入力
search_box = wait.until(
EC.element_to_be_clickable((By.NAME, "q"))
)
search_box.clear()
search_box.send_keys("Python automation")
search_box.submit()
# 結果リストの表示を確認
results = wait.until(
EC.presence_of_all_elements_located((By.CSS_SELECTOR, "div.g"))
)
print(f"検索結果数: {len(results)}")
# スクリーンショット保存
driver.save_screenshot("search_results.png")
finally:
driver.quit()
信頼性向上のためのベストプラクティス
- セレクタ戦略:IDやname属性を優先し、CSSセレクタやXPathは安定性を確認した上で使用。動的IDにはdata-testidなどのテスト専用属性を導入推奨
- タイムアウト設定:WebDriverWaitのタイムアウト値は、ネットワーク遅延やサーバー負荷を考慮して10〜20秒程度に設定
- エラーハンドリング:NoSuchElementExceptionやTimeoutExceptionを明示的にキャッチし、失敗時のスクリーンショットやログ出力を実装
- テスト分離:各テストケースは独立したブラウザセッションで実行。setup/teardownでdriverの生成・破棄を確実に行う
高度なユースケース対応
以下は、ポップアップやマルチタブ操作を含む複雑なシナリオの一例です:
# 新しいタブを開き、元のタブに戻る
original_handle = driver.current_window_handle
driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[-1])
driver.get("https://another-site.com")
# 元のタブへ復帰
driver.switch_to.window(original_handle)
# アラート処理(存在する場合)
try:
alert = driver.switch_to.alert
alert.accept() # または alert.dismiss()
except:
pass # アラートが表示されていない場合は無視