Selenium は Python から実際のブラウザを操作します。requests が空っぽの HTML しか返さず、必要なデータが JavaScript の実行後にしか現れないとき、手に取るべきツールが Selenium です。このガイドでは、2026 年に実際に機能する形で Selenium Web Scraping を解説します。組み込みのドライバー管理を備えた Selenium 4(chromedriver のダウンロードは不要)、新しいヘッドレスモード、By. ロケーター、そして time.sleep の当てずっぽうを置き換える明示的な待機です。すべてのサンプルはそのまま実行できます。
scraping 自体が初めてなら、まずはピラーガイドの web scraping with Python から始めてください。この記事は CSS セレクターが何かを知っている前提で、静的な HTML が終わり headless browser が始まるところから話を進めます。
Selenium が本当に必要になるとき
Selenium の本領はブラウザ自動化とテストで、そこでは本当に優秀です。W3C WebDriver 標準を話し、実際の Chrome/Firefox/Edge を操作し、20 年分の実戦経験を積んでいます。scraping では、その力に見合うのは特定の状況だけです。
| 状況 | 適切なツール |
|---|---|
データが最初の HTML にある(view-source で見える) | requests + BeautifulSoup — BeautifulSoup tutorial を参照 |
| データはページが呼び出す JSON API から届く | その API を直接叩く requests(まず Network タブを確認) |
| データが JavaScript の実行後にのみ描画される | Selenium または Playwright |
| データがクリック・スクロール・入力の後にのみ現れる | Selenium または Playwright |
| スクリーンショットや PDF レンダリングが必要 | Selenium または Playwright |
最初の 2 行は見た目以上に重要です。実際のブラウザは 1 ページに数秒と数百メガバイトを費やしますが、素の HTTP リクエストはミリ秒で済みます。Selenium を書き始める前に DevTools を開き、Network タブを眺めて、「JavaScript でしか取れない」はずのデータが実は整った JSON エンドポイントに載っていて直接呼べるのではないか、を確認してください。ざっくり半分のケースでは実際そうなっていて、それこそが web scraping with Python のツールキット全体の出番です。答えが本当にノーのときにだけ、Selenium に手を伸ばしましょう。
2026 年のセットアップ: pip install 一発、ドライバーのダウンロード不要
この部分は劇的に良くなりました。Selenium 4.6 以降、Selenium Manager がパッケージに同梱されています。インストール済みのブラウザを検出し、対応するドライバーバイナリをダウンロードしてキャッシュします。かつての儀式 — chromedriver をダウンロードし、バージョンを合わせ、PATH を直し、あるいは webdriver-manager を継ぎ足す — はもう過去のものです。webdriver-manager をインストールしろと言うチュートリアルは、時代遅れです。
python -m venv venv && source venv/bin/activate
pip install selenium
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("--headless=new") # the current headless mode
options.add_argument("--window-size=1920,1080") # default is 800x600 — breaks responsive layouts
driver = webdriver.Chrome(options=options) # Selenium Manager fetches the driver on first run
driver.get("https://www.selenium.dev")
print(driver.title)
driver.quit()
説明しておく価値のある 2 つのフラグ:
--headless=newは Chrome のモダンなヘッドレスモードです。旧来の--headlessフラグよりもヘッドありの Chrome とはるかに多くのコードを共有しているため、ページは画面上と同じようにレンダリングされます。サーバーや CI ではこれを使い、デバッグ中は外して、ブラウザが動く様子を目で確認しましょう。--window-size=1920,1080が重要なのは、ヘッドレスのデフォルトが 800x600 で、レスポンシブサイトが静かにモバイルレイアウトを返してくるからです — そうなるとデスクトップ用のセレクターは何にもマッチしません。
scraping の基本ワークフロー
ループは常に同じです。ページに移動し、コンテンツを待ち、By. ロケーターで要素を見つけ、テキストと属性を素の dict に取り出します。以下は、すべてを JavaScript でレンダリングする練習サイト quotes.toscrape.com/js に対する例です(素の requests.get では引用が 0 件になります)。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
options = webdriver.ChromeOptions()
options.add_argument("--headless=new")
driver = webdriver.Chrome(options=options)
try:
driver.get("https://quotes.toscrape.com/js/")
# Block until at least one quote card exists in the DOM (max 10s)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".quote"))
)
quotes = []
for card in driver.find_elements(By.CSS_SELECTOR, ".quote"):
quotes.append({
"text": card.find_element(By.CSS_SELECTOR, ".text").text,
"author": card.find_element(By.CSS_SELECTOR, ".author").text,
"tags": [t.text for t in card.find_elements(By.CSS_SELECTOR, ".tag")],
})
print(f"scraped {len(quotes)} quotes")
print(quotes[0])
finally:
driver.quit()
古いチュートリアルがまだ大量に出回っているので、モダンな API についての補足です。
- ロケーターは
find_element(By.CSS_SELECTOR, "...")です。 旧来のfind_element_by_css_selector系ヘルパーは Selenium 4.3 で削除されました — それらを使うコードは今ではAttributeErrorを投げます。By.CSS_SELECTORでほぼすべてをカバーでき、By.IDとBy.XPATHが隙間を埋めます(テキスト内容で選択できるのは XPath です)。 find_elementとfind_elements: 単数形はマッチがないとNoSuchElementExceptionを投げ、複数形は空のリストを返します。カードのグリッドには複数形を使い、続いて各カードにスコープを絞った単数形を使います —card.find_element(...)はそのカードの内側だけを検索します。- 属性は
element.get_attribute("href")(または"src"、"data-id"など)で、表示テキストはelement.textで取得します。 try/finallyとdriver.quit()— これがないと、クラッシュした実行のたびに Chrome プロセスが漏れ、10 回もクラッシュすればマシンが悲鳴を上げます。
実際の操作: クリック、スクロール、入力
Selenium のオーバーヘッドを受け入れた理由は、操作です。3 つのパターンでほとんどのサイトをカバーできます。
「load more」ボタンを消えるまでクリックする。 クリック可能になるのを待ち、クリックし、繰り返します。ボタンがなくなればループは終わります。
from selenium.common.exceptions import TimeoutException
while True:
try:
button = WebDriverWait(driver, 5).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "button.load-more"))
)
button.click()
except TimeoutException:
break # no more button — everything is loaded
無限スクロールのフィードをたどる。 最下部までスクロールし、新しいコンテンツの到着を待ち、ページの高さが伸びなくなったら止めます。
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
try:
WebDriverWait(driver, 5).until(
lambda d: d.execute_script("return document.body.scrollHeight") > last_height
)
last_height = driver.execute_script("return document.body.scrollHeight")
except TimeoutException:
break # height stopped growing — feed exhausted
検索ボックスに入力する。 send_keys はユーザーのように入力し、Keys.RETURN が送信します。
from selenium.webdriver.common.keys import Keys
box = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.CSS_SELECTOR, "input[name='q']"))
)
box.clear()
box.send_keys("mechanical keyboard", Keys.RETURN)
WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, ".result"))
)
どの操作の後も、抽出の前にその効果(新しいカード、変わった高さ、結果コンテナ)を待ってください — クリックが戻ってきたことは、ページが反応し終えたことを意味しません。
よくある失敗とその直し方
どの Selenium スクレイパーも、いずれこれらに出会います。直し方が「sleep を足す」であることは、ほぼありません。
| Exception | 意味 | 直し方 |
|---|---|---|
StaleElementReferenceException | 要素への参照を保持している間に、ページがその要素を再レンダリングした(クリックや AJAX 更新の後によく起きる)。古い参照は、もう存在しない DOM ノードを指している。 | ページを変化させる操作の後は要素を探し直す。ループでは、保存済みのリストを回すのではなく、毎回 find_elements を実行し直す。 |
ElementNotInteractableException / ElementClickInterceptedException | 要素は存在するが、非表示・サイズゼロ・何かに覆われている(Cookie バナー、固定ヘッダー、モーダル)。 | element_to_be_clickable を待つ、先にオーバーレイを閉じる、またはクリック前に driver.execute_script("arguments[0].scrollIntoView();", el) を実行する。 |
TimeoutException | WebDriverWait の条件が一度も真にならなかった。セレクターが間違っているか、コンテンツが iframe 内で読み込まれるか、サイトがブロックページを返した。 | 発生時に driver.title を出力し、driver.page_source を保存する — コンテンツの代わりに CAPTCHA や「verify you are human」ページが見つかることが多い。iframe は driver.switch_to.frame(...) で確認する。 |
NoSuchElementException | 単数形の find_element が何も見つけられなかった — 原因は上とほぼ同じで、待機が絡まないだけ。 | まず待ってから探す。または find_elements を使って空リストを処理する。 |
3 行目は強調に値します。TimeoutException は、セレクター問題の衣装を着た検出問題であることが少なくありません。 そこで、正直なセクションに進みましょう。
正直な話: Selenium は遅く、検出される
実際のブラウザには、2 つのコストが必ずついてきます。
速度と重さ。 ブラウザセッションは 1 ページに数秒と約 300-500 MB の RAM を消費しますが、HTTP リクエストはミリ秒とほぼゼロで済みます。10 ページなら無視できますが、10 万ページならサーバーの艦隊と、あなたが保守することになるキューイングシステムです。
検出。 素の状態では、Selenium が操作する Chrome は自ら正体を明かします。navigator.webdriver は true になり、さらに数十のより微妙なシグナル — TLS ハンドシェイク、欠けているプラグイン、canvas やフォントの癖、データセンター IP — が browser fingerprinting システムに流れ込み、最初のセレクターが動く前にボットと判定されます。症状は rate limiting、終わらない CAPTCHA の壁、あるいは静かに混入するゴミデータです。
undetected-chromedriver や SeleniumBase の UC モードのようなツールは、最も目立つシグナルにパッチを当てますし、実際に機能します — ベンダーが新しいチェックを出すまでは。そして彼らはそれを絶え間なく続けます。自動化の検出こそが彼らのビジネスそのものだからです。これは、あなたが趣味人で、相手が防衛産業という軍拡競争です。全体像は scraping sites that block bots にまとめました。要約すると、ブラウザへのパッチ当てはゴールではなく、終わらないランニングマシンです。
では Playwright は? Playwright はより新しい代替です。自動待機するロケーターを標準装備し、ヘッドレス動作はより速く安定していて、async をサポートし、scraping に限れば API もより快適です。それでも Selenium が勝つのは、実ブラウザの最も広いマトリクス、WebDriver 標準、10 年分の Stack Overflow の回答、主要 4 言語以外のバインディングが必要なとき — そして QA チームのデフォルトであり続けるのにも、それだけの理由があります。新規の scraping 専用プロジェクトなら、私たちはたいてい Playwright から始めます。ブラウザ横断で実ユーザーのカバレッジを再現しなければならない自動化なら Selenium です。ただし、検出のされにくさはどちらも変わりません — フィンガープリンティングシステムは、どのライブラリがマウスを動かしているかなど気にしないのです。
スケールアウト: 構造化 API がブラウザの艦隊に勝つとき
大規模化で本当に問われる判断はここです。ターゲットが大きく守りの固いプラットフォーム — Amazon、Google、ソーシャルネットワーク — の場合、Selenium の道はこうなります。プロキシ、フィンガープリントのパッチ、CAPTCHA 対応、リトライロジック、リデザインのたびに壊れる HTML パーサー、そしてブラウザを走らせるサーバー群。1 つ 1 つは実現可能でも、まとめればパートタイムのインフラ業務です。
代替案は、そのインフラをエンドポイントの裏側で運用し、構造化された JSON を返す web scraping API です。Selenium と待機とパースで約 40 行かかる Amazon 検索が、HTTP リクエスト 1 回になります。
import requests
resp = requests.get(
"https://api.crawlora.net/api/v1/amazon/search",
params={"k": "mechanical keyboard"},
headers={"x-api-key": "YOUR_API_KEY"},
)
products = resp.json()["data"] # structured fields — no parser to maintain
ブラウザなし、ドライバーなし、子守りするセレクターなし — さらに Crawlora は pay-on-success で、課金されるのは成功した 2xx レスポンスだけです。ブロックされたリクエストや失敗したリクエストは 1 円もかかりません。多くのチームが落ち着く妥当な分担はこうです。独自の操作が必要なサイトや、純粋にブラウザ自動化ツールとして正しい場面には Selenium を。大量アクセスで防御の固いプラットフォームには構造化 API を。 コストは自分で比較できます — ブラウザ艦隊の計算と per-request pricing を突き合わせ、コードを書く前に playground でエンドポイントを試してください。
- まず Network タブを確認した — データはすでに requests で叩ける JSON エンドポイントにないか?
- pip install selenium(4.6+)で、ドライバーは Selenium Manager に任せる — chromedriver のダウンロードは不要
- --headless=new を明示的な --window-size とともに使っている
- 待機はすべて WebDriverWait + expected_conditions — time.sleep はゼロ
- finally ブロックで driver.quit() を呼び、クラッシュした実行がブラウザを漏らさない
- TimeoutException が出たら、セレクターを疑う前に page_source をダンプしてブロックページを確認した
- スケールに正直である: 独自操作は Selenium、大量アクセスの防御されたプラットフォームは構造化 API
手強いターゲットにブラウザの艦隊は不要
Amazon、Google をはじめ 700 以上のエンドポイントから構造化 JSON を取得 — プロキシ・レンダリング・リトライはお任せで、課金は成功した 2xx レスポンスのみ。毎月 2,000 クレジット無料、カード不要。
関連記事
- Web scraping with Python: the complete guide — ピラー記事: requests、パース、保存、そしてブラウザへ移行すべきタイミング
- BeautifulSoup tutorial — HTML が静的なときのより速い道
- Web scraping with Playwright — 上で比較したモダンなブラウザ自動化の代替
- Scraping sites that block bots — 検出の軍拡競争の全貌
よくある質問
Selenium は web scraping に向いていますか?
はい。データが JavaScript の実行後、またはクリックやスクロールといった操作の後にしか現れない場合に向いています。Selenium は実際のブラウザを操作するため、ユーザーが見るものをそのまま見られます。静的な HTML には過剰で、requests と BeautifulSoup による素の HTTP リクエストのほうが 10-50 倍速く、はるかに軽量です。
Selenium と BeautifulSoup はどちらを使うべきですか?
この 2 つは別の問題を解決します。BeautifulSoup はすでに取得した HTML をパースし、Selenium はその HTML をそもそも生成するブラウザを動かします。データがページソースや JSON エンドポイントにあるなら requests と BeautifulSoup を、クライアントサイドで描画されたりクリックやスクロールが必要なら Selenium を使いましょう。その場合も driver.page_source を BeautifulSoup に渡してパースできます。
Selenium のために chromedriver をダウンロードする必要はまだありますか?
いいえ。Selenium 4.6 以降、組み込みの Selenium Manager がインストール済みのブラウザを検出し、対応するドライバーを自動でダウンロードします。pip install selenium だけでセットアップは完了です。chromedriver の個別ダウンロードや webdriver-manager パッケージはもう不要です。
Web サイトは Selenium を検出できますか?
はい。Selenium が操作する Chrome は navigator.webdriver を true にし、ブラウザフィンガープリンティングシステムは TLS ハンドシェイク、欠けているプラグイン、canvas の癖、データセンター IP など、より微妙なシグナルも多数読み取ります。undetected-chromedriver のようなパッチは目立つ痕跡を隠しますが、アンチボットベンダーはチェックを絶えず更新するため、回避は一度きりの修正ではなく継続的な軍拡競争になります。
Selenium でページの読み込みを待つには?
time.sleep ではなく WebDriverWait と expected_conditions を使います。WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".quote"))) は要素が存在するまでポーリングし、存在した瞬間に戻ります。速いページではより速く、遅いページにも耐えます。クリックの前には element_to_be_clickable を、描画済みのコンテンツが必要なときは visibility_of_element_located を使いましょう。
web scraping には Selenium と Playwright のどちらが良いですか?
新規の scraping 専用プロジェクトなら、たいてい Playwright が勝ちます。自動待機するロケーター、より速いヘッドレス実行、async サポートが理由です。Selenium は最も広い実ブラウザカバレッジ、W3C WebDriver 標準、そしてエコシステムで勝り、QA チームが今もデフォルトにしている理由でもあります。検出のされにくさはどちらも同じです。アンチボットシステムがフィンガープリントするのはブラウザであって、それを動かすライブラリではありません。
Selenium スクレイパーで TimeoutException が出るのはなぜですか?
TimeoutException は、待機条件が一度も真にならなかったことを意味します。よくある原因は、セレクターの誤り、切り替えていない iframe 内のコンテンツ、そして非常に多いのが、コンテンツの代わりにブロックページや CAPTCHA が返されているケースです。発生時に driver.page_source をダンプしてください。アンチボットページが見えたら、問題は検出であって、セレクターではありません。
