Python Selenium完全ガイド – Web自動化・動的サイトスクレイピングの決定版
Seleniumは、Webブラウザを自動操作するための強力なツールです。JavaScriptで動的に生成されるコンテンツのスクレイピング、Webアプリケーションのテスト自動化、繰り返し作業の自動化など、幅広い用途で活用されています。この記事では、Python SeleniumとWebDriverの基本から高度なテクニックまで、実践的なサンプルコードとともに詳しく解説します。
Seleniumとは
Seleniumは、Webブラウザを自動制御するためのフレームワークです。実際のブラウザを操作するため、JavaScriptによる動的コンテンツも取得でき、ユーザーの操作を完全に再現できます。
主な特徴
- 実ブラウザ操作: Chrome、Firefox、Safari、Edgeなどをサポート
- JavaScript対応: 動的に生成されるコンテンツも取得可能
- 多様な操作: クリック、入力、スクロール、スクリーンショットなど
- 待機機能: 要素の読み込み完了まで自動待機
インストールと環境設定
ライブラリのインストール
pip install selenium webdriver-manager
WebDriverの自動管理
from selenium import webdriver
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(ChromeDriverManager().install())
基本的なセットアップ
from selenium import webdriver
from selenium.webdriver.common.by import By
# ブラウザの起動
driver = webdriver.Chrome()
driver.get("https://example.com")
print(driver.title)
driver.quit()
基本的な操作
ページの読み込み
driver = webdriver.Chrome()
driver.get("https://www.google.com")
print(f"現在のURL: {driver.current_url}")
print(f"ページタイトル: {driver.title}")
要素の検索
# IDで検索
element = driver.find_element(By.ID, "search-box")
# クラス名で検索
element = driver.find_element(By.CLASS_NAME, "button")
# CSS セレクタで検索
element = driver.find_element(By.CSS_SELECTOR, "div.content > p")
# XPathで検索
element = driver.find_element(By.XPATH, "//input[@type='text']")
複数要素の検索
# すべてのリンクを取得
links = driver.find_elements(By.TAG_NAME, "a")
print(f"リンク数: {len(links)}")
for link in links[:5]:
print(f"テキスト: {link.text}, URL: {link.get_attribute('href')}")
フォーム操作
テキスト入力
search_box = driver.find_element(By.NAME, "q")
search_box.clear()
search_box.send_keys("Python Selenium")
ボタンのクリック
search_button = driver.find_element(By.NAME, "btnK")
search_button.click()
セレクトボックスの操作
from selenium.webdriver.support.ui import Select
select_element = driver.find_element(By.ID, "dropdown")
select = Select(select_element)
# インデックスで選択
select.select_by_index(1)
# 値で選択
select.select_by_value("option2")
# 表示テキストで選択
select.select_by_visible_text("オプション3")
チェックボックス・ラジオボタン
checkbox = driver.find_element(By.ID, "agree")
if not checkbox.is_selected():
checkbox.click()
radio_button = driver.find_element(By.NAME, "gender")
radio_button.click()
待機処理
明示的待機
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# 要素が表示されるまで最大10秒待機
wait = WebDriverWait(driver, 10)
element = wait.until(EC.presence_of_element_located((By.ID, "dynamic-content")))
よく使用される待機条件
# 要素がクリック可能になるまで待機
clickable = wait.until(EC.element_to_be_clickable((By.ID, "submit-btn")))
# テキストが含まれるまで待機
text_present = wait.until(EC.text_to_be_present_in_element((By.ID, "status"), "完了"))
# 要素が非表示になるまで待機
invisible = wait.until(EC.invisibility_of_element_located((By.ID, "loading")))
暗黙的待機
driver.implicitly_wait(10) # 10秒まで要素の出現を待機
element = driver.find_element(By.ID, "delayed-element")
ブラウザオプション
Chrome オプション
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless') # ヘッドレスモード
options.add_argument('--no-sandbox') # サンドボックス無効
options.add_argument('--disable-dev-shm-usage') # /dev/shm使用無効
options.add_argument('--window-size=1920,1080') # ウィンドウサイズ
driver = webdriver.Chrome(options=options)
Firefox オプション
from selenium.webdriver.firefox.options import Options
options = Options()
options.add_argument('--headless')
driver = webdriver.Firefox(options=options)
User-Agentの設定
options = Options()
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36')
driver = webdriver.Chrome(options=options)
JavaScript の実行
基本的な JavaScript 実行
# ページの最下部までスクロール
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 要素を強制的にクリック
element = driver.find_element(By.ID, "hidden-button")
driver.execute_script("arguments[0].click();", element)
戻り値のある JavaScript
# ページの高さを取得
height = driver.execute_script("return document.body.scrollHeight;")
print(f"ページ高さ: {height}px")
# ローカルストレージの操作
driver.execute_script("localStorage.setItem('key', 'value');")
value = driver.execute_script("return localStorage.getItem('key');")
非同期 JavaScript の実行
# 非同期処理の実行
script = """
var callback = arguments[arguments.length - 1];
setTimeout(function() {
callback('非同期処理完了');
}, 2000);
"""
result = driver.execute_async_script(script)
print(result) # 非同期処理完了
ウィンドウとタブの管理
新しいタブの開始
# 新しいタブを開く
driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[1])
driver.get("https://example.com")
タブの切り替え
# 最初のタブに戻る
driver.switch_to.window(driver.window_handles[0])
# すべてのタブを閉じる
for handle in driver.window_handles[1:]:
driver.switch_to.window(handle)
driver.close()
driver.switch_to.window(driver.window_handles[0])
ウィンドウサイズの操作
# ウィンドウサイズの変更
driver.set_window_size(1200, 800)
# ウィンドウの最大化
driver.maximize_window()
# 現在のウィンドウサイズを取得
size = driver.get_window_size()
print(f"幅: {size['width']}, 高さ: {size['height']}")
アラートとポップアップの処理
アラートの処理
from selenium.webdriver.support.ui import Alert
# アラートが表示されるまで待機
wait.until(EC.alert_is_present())
alert = Alert(driver)
print(f"アラートテキスト: {alert.text}")
alert.accept() # OKボタンをクリック
# alert.dismiss() # キャンセルボタンをクリック
確認ダイアログの処理
# 確認ダイアログの処理
alert = Alert(driver)
alert.accept() # OK
# alert.dismiss() # キャンセル
プロンプトダイアログの処理
alert = Alert(driver)
alert.send_keys("入力テキスト")
alert.accept()
フレームとiframeの操作
フレームの切り替え
# iframe に切り替え
iframe = driver.find_element(By.TAG_NAME, "iframe")
driver.switch_to.frame(iframe)
# iframe 内の要素を操作
inner_element = driver.find_element(By.ID, "inner-content")
# メインコンテンツに戻る
driver.switch_to.default_content()
フレーム名での切り替え
# フレーム名で切り替え
driver.switch_to.frame("frame-name")
# フレームインデックスで切り替え
driver.switch_to.frame(0)
ファイルのアップロードとダウンロード
ファイルアップロード
file_input = driver.find_element(By.TYPE, "file")
file_input.send_keys("/path/to/file.txt")
upload_button = driver.find_element(By.ID, "upload-btn")
upload_button.click()
ダウンロード設定
import os
download_dir = os.path.join(os.getcwd(), "downloads")
options = Options()
prefs = {
"download.default_directory": download_dir,
"download.prompt_for_download": False,
"directory_upgrade": True,
"safebrowsing.enabled": True
}
options.add_experimental_option("prefs", prefs)
driver = webdriver.Chrome(options=options)
スクリーンショットとページソース
スクリーンショットの撮影
# ページ全体のスクリーンショット
driver.save_screenshot("screenshot.png")
# 特定要素のスクリーンショット
element = driver.find_element(By.ID, "content")
element.screenshot("element.png")
ページソースの取得
# 現在のページソースを取得
page_source = driver.page_source
print(f"ページソース長: {len(page_source)}")
# ファイルに保存
with open("page_source.html", "w", encoding="utf-8") as f:
f.write(page_source)
実践的なスクレイピング例
1. 動的検索結果の取得
def scrape_search_results(query):
driver = webdriver.Chrome()
driver.get("https://example-search.com")
# 検索実行
search_box = driver.find_element(By.NAME, "q")
search_box.send_keys(query)
search_box.submit()
# 結果の待機と取得
wait = WebDriverWait(driver, 10)
results = wait.until(EC.presence_of_all_elements_located((By.CLASS_NAME, "result")))
data = []
for result in results[:10]:
title = result.find_element(By.TAG_NAME, "h3").text
link = result.find_element(By.TAG_NAME, "a").get_attribute("href")
data.append({"title": title, "link": link})
driver.quit()
return data
2. 無限スクロールページの処理
def scrape_infinite_scroll(url):
driver = webdriver.Chrome()
driver.get(url)
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
# 最下部までスクロール
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 新しいコンテンツの読み込み待機
time.sleep(2)
new_height = driver.execute_script("return document.body.scrollHeight")
if new_height == last_height:
break
last_height = new_height
# データ取得
items = driver.find_elements(By.CLASS_NAME, "item")
data = [item.text for item in items]
driver.quit()
return data
3. ログインが必要なサイトのスクレイピング
def scrape_with_login(username, password):
driver = webdriver.Chrome()
driver.get("https://example.com/login")
# ログイン処理
driver.find_element(By.NAME, "username").send_keys(username)
driver.find_element(By.NAME, "password").send_keys(password)
driver.find_element(By.TYPE, "submit").click()
# ログイン完了を待機
wait = WebDriverWait(driver, 10)
wait.until(EC.presence_of_element_located((By.ID, "user-dashboard")))
# プロテクトされたページにアクセス
driver.get("https://example.com/protected-page")
# データ取得
protected_data = driver.find_element(By.ID, "protected-content").text
driver.quit()
return protected_data
4. フォーム送信の自動化
def automate_form_submission(form_data):
driver = webdriver.Chrome()
driver.get("https://example.com/form")
# フォーム入力
for field_name, value in form_data.items():
element = driver.find_element(By.NAME, field_name)
if element.tag_name == "select":
Select(element).select_by_visible_text(value)
else:
element.clear()
element.send_keys(value)
# 送信
driver.find_element(By.TYPE, "submit").click()
# 結果の確認
wait = WebDriverWait(driver, 10)
success_message = wait.until(EC.presence_of_element_located((By.CLASS_NAME, "success")))
result = success_message.text
driver.quit()
return result
パフォーマンス最適化
ヘッドレスモードの活用
def create_headless_driver():
options = Options()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-images') # 画像読み込み無効
options.add_argument('--disable-javascript') # JS無効(必要に応じて)
return webdriver.Chrome(options=options)
ページロード戦略
options = Options()
options.page_load_strategy = 'eager' # DOM完了で続行(デフォルト: 'normal')
driver = webdriver.Chrome(options=options)
並行処理
from concurrent.futures import ThreadPoolExecutor
import threading
class ThreadSafeDriver:
_local = threading.local()
@classmethod
def get_driver(cls):
if not hasattr(cls._local, 'driver'):
cls._local.driver = webdriver.Chrome()
return cls._local.driver
def scrape_url(url):
driver = ThreadSafeDriver.get_driver()
driver.get(url)
return driver.title
# 並行実行
urls = ["https://example1.com", "https://example2.com", "https://example3.com"]
with ThreadPoolExecutor(max_workers=3) as executor:
results = list(executor.map(scrape_url, urls))
エラーハンドリング
基本的な例外処理
from selenium.common.exceptions import NoSuchElementException, TimeoutException
def safe_find_element(driver, by, value):
try:
element = driver.find_element(by, value)
return element
except NoSuchElementException:
print(f"要素が見つかりません: {value}")
return None
def safe_click(driver, by, value):
try:
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((by, value))
)
element.click()
return True
except TimeoutException:
print(f"要素がクリックできません: {value}")
return False
リトライ機能付きスクレイピング
import time
from functools import wraps
def retry(max_attempts=3, delay=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
print(f"試行 {attempt + 1} 失敗: {e}")
time.sleep(delay)
return None
return wrapper
return decorator
@retry(max_attempts=3, delay=2)
def scrape_with_retry(url):
driver = webdriver.Chrome()
driver.get(url)
title = driver.title
driver.quit()
return title
テスト自動化
単体テストとの連携
import unittest
class WebTestCase(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome()
self.driver.implicitly_wait(10)
def tearDown(self):
self.driver.quit()
def test_login_functionality(self):
self.driver.get("https://example.com/login")
username_field = self.driver.find_element(By.NAME, "username")
password_field = self.driver.find_element(By.NAME, "password")
login_button = self.driver.find_element(By.TYPE, "submit")
username_field.send_keys("testuser")
password_field.send_keys("password123")
login_button.click()
# ログイン成功の確認
welcome_message = self.driver.find_element(By.ID, "welcome")
self.assertIn("ようこそ", welcome_message.text)
if __name__ == "__main__":
unittest.main()
Page Object Model
class LoginPage:
def __init__(self, driver):
self.driver = driver
self.username_field = (By.NAME, "username")
self.password_field = (By.NAME, "password")
self.login_button = (By.TYPE, "submit")
def login(self, username, password):
self.driver.find_element(*self.username_field).send_keys(username)
self.driver.find_element(*self.password_field).send_keys(password)
self.driver.find_element(*self.login_button).click()
class DashboardPage:
def __init__(self, driver):
self.driver = driver
self.welcome_message = (By.ID, "welcome")
def get_welcome_text(self):
return self.driver.find_element(*self.welcome_message).text
# 使用例
driver = webdriver.Chrome()
driver.get("https://example.com/login")
login_page = LoginPage(driver)
login_page.login("testuser", "password123")
dashboard_page = DashboardPage(driver)
welcome_text = dashboard_page.get_welcome_text()
デバッグとトラブルシューティング
デバッグ用の便利な関数
def debug_element_info(driver, by, value):
try:
element = driver.find_element(by, value)
print(f"要素が見つかりました: {element.tag_name}")
print(f"テキスト: {element.text}")
print(f"表示状態: {element.is_displayed()}")
print(f"有効状態: {element.is_enabled()}")
print(f"位置: {element.location}")
print(f"サイズ: {element.size}")
except NoSuchElementException:
print(f"要素が見つかりません: {value}")
def debug_page_info(driver):
print(f"現在のURL: {driver.current_url}")
print(f"ページタイトル: {driver.title}")
print(f"ウィンドウサイズ: {driver.get_window_size()}")
print(f"ページソース長: {len(driver.page_source)}")
ログ設定
import logging
from selenium.webdriver.remote.remote_connection import LOGGER
# Seleniumのログレベルを設定
LOGGER.setLevel(logging.WARNING)
# カスタムログ設定
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('selenium.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
セキュリティとベストプラクティス
検出回避テクニック
def create_stealth_driver():
options = Options()
options.add_argument('--disable-blink-features=AutomationControlled')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
driver = webdriver.Chrome(options=options)
driver.execute_script("Object.defineProperty(navigator, 'webdriver', {get: () => undefined})")
return driver
人間らしい操作の実装
import random
from selenium.webdriver.common.action_chains import ActionChains
def human_like_typing(element, text, min_delay=0.05, max_delay=0.2):
for char in text:
element.send_keys(char)
time.sleep(random.uniform(min_delay, max_delay))
def human_like_click(driver, element):
actions = ActionChains(driver)
actions.move_to_element(element)
actions.pause(random.uniform(0.5, 1.5))
actions.click()
actions.perform()
プロキシの使用
def create_proxy_driver(proxy_host, proxy_port):
options = Options()
options.add_argument(f'--proxy-server=http://{proxy_host}:{proxy_port}')
return webdriver.Chrome(options=options)
まとめ
Seleniumは、動的なWebサイトの操作やテスト自動化において非常に強力なツールです。JavaScript重要のSPAサイトやログインが必要なサイトでも、実際のブラウザを操作することで確実にデータを取得できます。
主なポイント:
- 動的コンテンツ対応: JavaScriptで生成されるコンテンツも取得可能
- 豊富な操作: クリック、入力、スクロール、ファイル操作など
- 待機機能: 明示的・暗黙的待機で安定した動作
- ブラウザオプション: ヘッドレスモード、プロキシ設定など
- エラーハンドリング: 堅牢なスクリーピングのための例外処理
- パフォーマンス最適化: 並行処理、設定調整による高速化
Seleniumを使用する際は、対象サイトの利用規約を遵守し、サーバーに過度な負荷をかけないよう注意することが重要です。また、APIが提供されている場合は、SeleniumよりもAPIの使用を優先することをお勧めします。
参考リンク
適切な知識とマナーを持って、効果的なWeb自動化を実践しましょう。
■プロンプトだけでオリジナルアプリを開発・公開してみた!!
■AI時代の第一歩!「AI駆動開発コース」はじめました!
テックジム東京本校で先行開始。
■テックジム東京本校
「武田塾」のプログラミング版といえば「テックジム」。
講義動画なし、教科書なし。「進捗管理とコーチング」で効率学習。
より早く、より安く、しかも対面型のプログラミングスクールです。
<短期講習>5日で5万円の「Pythonミニキャンプ」開催中。
<月1開催>放送作家による映像ディレクター養成講座
<オンライン無料>ゼロから始めるPython爆速講座



