毎日おなじサイトを開いて、おなじ場所にログインして、おなじ数字を書き写す。そんな作業に心当たりはないでしょうか。
手順は完全に決まっているのに、なぜか人間がやるしかない。この歯がゆさをほどいてくれるのがSeleniumです。
Seleniumは、ブラウザそのものをPythonから動かすためのライブラリになります。クリックも文字入力も、コードで指示できます。
この記事では、Seleniumがどういう仕組みで動くのかを、実際に動くコードと一緒に順番に見ていきます。
Seleniumは、ブラウザを人の代わりに操作する道具¶
まず立ち位置をはっきりさせておきましょう。Seleniumは、ChromeやFirefoxといった本物のブラウザを外から操作するための道具です。
裏でこっそりHTMLを取ってくるのではありません。本物のブラウザが立ち上がり、実際にクリックされ、実際に文字が入力されます。
もともとはWebアプリのテストを自動化するために生まれた道具でした。人間が手でくり返していた動作確認を、機械に任せるためのものです。
その性質から、テスト以外の場面でも使われるようになりました。ログインが必要なページの巡回や、画面の定期的なチェックが代表例です。
操作の指示は、WebDriverという共通の決まりごとに沿って送られます。Pythonが命令を出し、ドライバーが受け取り、ブラウザが動く。この三段構えが基本の形です。
requestsやBeautifulSoupとは、取りにいく場所が違う¶
Webから情報を取る話になると、requestsやBeautifulSoupの名前も挙がりますよね。どれを選ぶべきか、先に整理しておきます。
分かれ目は、JavaScriptが動いたあとの画面を見られるかどうかです。三つを並べてみます。
| 道具 | 何をするもの | JavaScript後の画面 |
|---|---|---|
| requests | サーバーからHTMLを受け取る | 見られない |
| BeautifulSoup | 受け取ったHTMLから目的の部分を抜き出す | 元のHTML次第 |
| Selenium | ブラウザを丸ごと動かす | 見られる |
requestsが受け取るのは、サーバーが最初に返したHTMLだけです。そのあとJavaScriptが書き足した部分は、そこには載っていません。
最近のサイトは、中身をあとからJavaScriptで描くものが増えました。requestsで取ったHTMLに目当ての文字が見つからないとき、原因はたいていこれです。
Seleniumはブラウザに描かせたあとの状態を見ます。そのぶん動きは遅く、必要なメモリも増えます。
ですので順番としては、まずrequestsで足りるかを試すのが定石になります。【関連記事】Pythonのrequestsとは?WebからデータをとってくるHTTP通信の基本を初心者向けに解説
HTMLから目的の部分を抜き出す作業そのものは、BeautifulSoupの得意分野です。Seleniumで取得したHTMLを渡して組み合わせることもできます。【関連記事】PythonのBeautifulSoupとは?Webページから情報を取り出すスクレイピングの基本を初心者向けに解説
インストールから最初の1本まで¶
説明を読むより、手を動かしたほうが早いはずです。ここから実際にブラウザが開くところまで進みます。
ドライバーの用意は、もう要らない¶
Seleniumは標準ライブラリではないので、pipで入れるところから始めます。プロジェクトごとに仮想環境を作ってから入れると、あとで散らかりません。
pip install selenium
執筆時点の最新版は4.48.0で、2026年8月27日に公開されています。動かすにはPython 3.10以降が必要です。
仮想環境の作り方に不安があれば、先に土台を固めておくと安心です。【関連記事】Pythonの仮想環境(venv)って何のためにある?プロジェクトごとに混ぜない管理法
ここで、昔のSeleniumを知っている人ほど身構えます。以前はChromeDriverを自分でダウンロードし、ブラウザの更新に合わせて置き換える手間がありました。
いまは不要です。Selenium Managerという仕組みが4.6以降のすべてのリリースに同梱され、必要なドライバーを自動で見つけて取ってきてくれます。
取得したドライバーは ~/.cache/selenium に保存され、次からはそこから使い回されます。ドライバーの手配はSeleniumの仕事になった、といまは覚えておけば十分です。
数行でブラウザを開いてみる¶
準備ができたら、短いスクリプトを書いてみましょう。5行で動きます。
from selenium import webdriver
driver = webdriver.Chrome()
driver.get("https://www.python.org/")
print(driver.title)
driver.quit()
実行するとChromeが勝手に立ち上がり、ページを開き、タイトルを表示して閉じます。初めて見ると、少し驚くはずです。
最後の driver.quit() を忘れないでください。書き忘れると、ブラウザとドライバーが裏で生き残ります。
要素を見つけて、操作する¶
ページが開けたら、次は目的の場所を指し示す番です。Seleniumではこれを要素の取得と呼びます。
使うのは find_element() で、どうやって探すかを By で指定します。よく使う指定方法を並べておきます。
| 指定 | 探し方 | 向いている場面 |
|---|---|---|
By.ID |
id属性で探す | idが振られている入力欄 |
By.NAME |
name属性で探す | フォームの部品 |
By.CLASS_NAME |
class名で探す | 同じ見た目が並ぶ箇所 |
By.CSS_SELECTOR |
CSSの書き方で探す | 迷ったらこれ |
By.XPATH |
文書の構造をたどって探す | 他で届かないとき |
By.LINK_TEXT |
リンクの文字で探す | 文言が安定したリンク |
検索欄に文字を打ち込み、送信して結果を読むところまで書くと、こうなります。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get("https://example.com/search")
box = driver.find_element(By.NAME, "q")
box.send_keys("pathlib")
box.send_keys(Keys.RETURN)
for item in driver.find_elements(By.CSS_SELECTOR, ".result-title"):
print(item.text)
driver.quit()
find_element() は最初の1件だけを返し、find_elements() は該当するものをすべてリストで返します。見つからなかったときの挙動が違うので、ここは区別して覚えてください。
前者は例外を投げて止まり、後者は空のリストを返します。あるかどうか分からないものを調べたいときは、後者が扱いやすいはずです。
古い解説記事では driver.find_element_by_id("q") という書き方も見かけます。この形はSelenium 4.3.0で削除されているので、いま真似しても動きません。
取り出したデータをファイルに残すなら、csvモジュールが素直な相棒になります。【関連記事】Pythonのcsvモジュールとは?表データの読み書きと文字化けの防ぎ方を初心者向けに解説
Seleniumでいちばん大事なのは、待つこと¶
ここが初心者のつまずきどころの筆頭です。落ち着いて読んでみてください。
ブラウザは、コードの実行速度に比べればずっとのんびりしています。ページを開いた直後に要素を探すと、まだ描かれていなくて失敗します。
このとき出るのが NoSuchElementException です。手元では動くのに、時々だけ落ちる。この不安定さの正体は、ほとんどが待ち時間の不足だと思ってかまいません。
待ち方はふたつ用意されています。順番に見ていきます。
暗黙の待機で、全体にゆとりを持たせる¶
いちばん手軽なのは、要素が見つかるまで一定時間だけ粘るよう設定してしまう方法です。1行書けば、以降のすべての取得に効きます。
driver.implicitly_wait(5)
見つかった時点ですぐ次へ進むので、毎回きっちり5秒待つわけではありません。細かいことは考えず、全体をざっくり安定させたいときに向いています。
明示的な待機で、条件が整うまで待つ¶
もう少し賢く待ちたいときは、条件を決めて待ちます。要素が現れるまで、あるいは押せる状態になるまで、といった指定ができます。
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
wait = WebDriverWait(driver, timeout=10)
button = wait.until(EC.element_to_be_clickable((By.ID, "submit")))
button.click()
until() に渡す条件は expected_conditions にひととおり用意されています。要素の出現、表示、クリック可能といった状態が、そのまま関数の名前になっています。
条件が満たされれば即座に次へ進み、時間切れなら TimeoutException で止まります。無駄に待たず、必要な分だけ待てるのが利点です。
ひとつ注意があります。公式ドキュメントは、暗黙の待機と明示的な待機を混ぜないよう明確に警告しています。
両方を設定すると待ち時間の計算が読めなくなり、10秒と15秒の指定なのに20秒後に時間切れになることがある、と説明されています。どちらかに寄せる、これが安全な選び方です。
time.sleep() で数秒止める書き方も見かけますが、おすすめしません。速いときは無駄に待ち、遅いときは結局間に合わないからです。
画面を出さずに動かす¶
自動化が目的なら、ブラウザの画面はむしろ邪魔になります。裏で静かに動いてほしいですよね。
そのための設定がヘッドレスモードです。起動時にオプションとして渡します。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument("--headless=new")
options.add_argument("--window-size=1280,900")
with webdriver.Chrome(options=options) as driver:
driver.get("https://www.python.org/")
print(driver.title)
with を使うと、ブロックを抜けるときに終了処理が自動で走ります。driver.quit() の書き忘れが減るので、私はこの形をよく使います。
ウィンドウの大きさをわざわざ指定しているのには理由があります。画面が狭いとレイアウトが切り替わり、目的の要素が消えてしまうことがあるからです。
サーバー上で定期的に動かすところまで進めたくなったら、実行を仕込む側の知識も必要になります。【関連記事】Pythonで定期実行するには?cronとタスクスケジューラの基本
つまずきやすいところと、私の失敗¶
最後に、実際に触ると出会いやすい落とし穴をまとめておきます。先に知っておくと、無駄に悩まずに済みます。
まず、相手のサイトの利用規約とrobots.txtは必ず確認してください。ブラウザを動かせることと、動かしていいことは別の話です。
短い間隔で連打すれば、相手のサーバーに負荷をかけます。アクセスの間隔は必ず空けましょう。
要素の指定にも癖があります。自動生成されたclass名を頼りにすると、サイトの更新であっけなく壊れます。
私は10年ほどエンジニアとして開発に関わってきましたが、この壊れやすさで痛い目に遭ったことがあります。社内の申請システムの入力を自動化したところ、半年後の画面改修でスクリプトが全滅しました。
原因は、XPathで画面の並び順を指定していたことでした。項目がひとつ増えただけで、指定していた位置がすべてずれたのです。
いまはidやname、それが無ければ画面に見えている文言を手がかりにするようにしています。人が見て意味の分かる目印ほど、改修で残りやすいからです。
もうひとつは、自動テストの環境で driver.quit() を書き忘れたときの話です。Chromeのプロセスが残り続け、実行のたびにメモリを食いつぶし、原因の特定に半日かかりました。
それ以来、必ず with で囲むか、try と finally で終了処理を守るようにしています。
まとめ¶
Seleniumは、本物のブラウザをPythonから操作するライブラリです。JavaScriptで描かれる画面にも、ログインが要るページにも手が届きます。
覚える順番はいたってシンプルです。ブラウザを開き、要素を見つけ、操作する。そして待つ。
とくに待ち方だけは、最初にきちんと押さえておいてください。不安定なSeleniumのコードは、たいてい待ち方の問題です。
まずは手元のブラウザでページを開き、タイトルを表示するあの5行から始めてみましょう。勝手に動き出すブラウザを見た瞬間の驚きが、次の一歩を運んでくれるはずです。
ここまでお読みいただきありがとうございました。