
BS+Requestで取得できない要素を取得したいんだよね。

その悩み、Seleniumで解決できます。
ウェブサイトの特定の場所をクリックしたり、入力フォームにテキストを入力したりとBeautiful Soup+Requestで実現できない操作を実現するのがSeleniumです。
この記事では、PythonとSeleniumを組み合わせることで、動的なウェブサイトから効率的にデータを抽出する方法を基礎から応用まで体系的に解説します。
- PythonとSeleniumによる動的サイトのデータ抽出方法
- 環境構築からデータ活用までの実践的な5ステップ
- Selenium利用時の主要エラーと解決策
- 実際にSeleniumを使ったサンプル事例
本記事は、スクレイピングを推奨・助長する目的で執筆しておりませんが、教育目的としてログイン画面を突破したり複数のページ遷移したり自動化を実現するためにも、ぜひ本記事を参考にしてください。
細かい前置きはいいから早く実践に行きたいという方は以下のリンクから実践のフェーズに移動できます。
>>Seleniumのスクレイピング実践へ移動する
Pythonスクレイピング 動的サイトを制するSeleniumの力
手作業でのデータ収集にうんざりしていませんか。
JavaScriptで動的にコンテンツが生成されるウェブサイトや、ログインが必要な複雑なページからのデータ抽出は、従来のスクレイピング手法では非常に難しいものです。
そんな悩みを解決するのがSeleniumの強力な機能です。
ここでは、「従来のスクレイピングでは抽出できない情報」とは何かを具体的に掘り下げ、「JavaScriptで動的に生成されるコンテンツ」の正体を明らかにします。
さらに「なぜSeleniumはウェブブラウザを操作できるのか」という仕組みと、他のスクレイピングライブラリである「Requests・BeautifulSoupとの使い分けと利点」について詳しく解説しますね。
PythonとSeleniumを組み合わせることで、これまでアクセスできなかったウェブサイトの情報も効率的に取得し、あなたのデータ収集業務を劇的に変えることができます。
従来のスクレイピングでは抽出できない情報
「従来のスクレイピング」とは、主にRequestsライブラリでHTMLを取得し、BeautifulSoupで解析する方法を指します。
この方法では、ウェブサーバーから送られてくる静的なHTMLコンテンツは問題なく取得できますが、ログイン後のページや、クリックしないと表示されない隠れたコンテンツ、Ajaxで後から読み込まれるデータなど、ユーザーのアクションによって変化する情報は取得が非常に困難でした。
例えば、オンラインショッピングサイトで商品をカートに入れた後のページや、特定の検索フィルターを適用した後の結果ページなど、手動で操作が必要な場面での情報取得は、まさに一筋縄ではいかない領域だと感じていましたかと。

なんで頑張ってコード書いても、クリックしないと見れない情報は取れないんだろう?

その悩み、Seleniumが解決できます。
つまり、RequestsとBeautifulSoupだけでは、ウェブページの「見える情報」全てを捉えることは難しく、動的な要素が多い現代のウェブサイトでは限界があると言えるでしょう。
JavaScriptで動的に生成されるコンテンツ
「JavaScriptで動的に生成されるコンテンツ」とは、ウェブサイトが表示された後にJavaScriptというプログラミング言語が実行されることで、内容や見た目が変化したり、新たな要素が追加されたりするウェブページのことを指します。
例えば、Googleの検索結果ページで下にスクロールすると、次々と新しい検索結果が表示される「無限スクロール」や、グラフや地図などのインタラクティブな要素が、まさにこの動的生成コンテンツの代表例です。
これらのコンテンツは、ブラウザがJavaScriptコードを実行してから初めて表示されるため、従来のスクレイピングでは「ただの空白」としてしか認識されませんでした。
実際、わたしも初めて動的サイトにぶつかった時、「これじゃ全くデータが取れないじゃないか!」と頭を抱えました。

スクロールしないと出てこない情報、どうやって集めたらいいの?

リアルなブラウザ操作をシミュレーションすることで対応可能です。
動的に生成されるコンテンツは、ユーザー体験を豊かにする一方で、スクレイピングにとっては大きな壁となる要素だと理解しておく必要があります。
なぜSeleniumはウェブブラウザを操作できるのか
Seleniumがウェブブラウザを操作できる理由は、「WebDriver」という専用のドライバーを介して、実際のウェブブラウザ(Google ChromeやFirefoxなど)を直接コントロールするためです。
このWebDriverは、まるで人間がブラウザを触るかのように、ウェブページを開いたり、ボタンをクリックしたり、テキストを入力したりといった操作を、あなたのプログラムからの指示で忠実に実行します。
例えば、あなたはコードで「このテキストボックスに文字を入力して」と指示を出すだけで、WebDriverが実際のブラウザ画面上でその通りに文字を打ち込み、そして「このログインボタンを押して」と命令すれば、ログイン操作も自動で実行されます。
これにより、JavaScriptで動的に表示されるコンテンツも、ブラウザが完全にレンダリング(表示)した状態で情報を取り出せるのが大きな強みです。

仮想ブラウザって何だろう?実際に画面は見えないけど本当に動いているの?

ブラウザを裏で動かし、まるであなたが手で操作しているかのようにウェブサイトに働きかけます。
SeleniumとWebDriverの組み合わせによって、通常のブラウザが処理できること全てがスクレイピングの対象となり、非常に多くのウェブサイトからデータを効率良く収集できるのです。
Requests・BeautifulSoupとの使い分けと利点
Requests、BeautifulSoup、そしてSeleniumは、それぞれ異なる得意分野を持つPythonのスクレイピングライブラリであり、ウェブサイトの特性に応じて適切に使い分けることが効率的なデータ収集の鍵となります。
RequestsはHTTPリクエストを送信してHTMLを取得するライブラリで、非常に高速な処理が可能です。
BeautifulSoupは取得したHTMLを解析し、目的の要素を抽出するのに特化しています。
対してSeleniumは、JavaScriptで動的に生成されるコンテンツや、ログイン、ボタンクリックといった「ブラウザ操作」が必要な場面で真価を発揮します。
処理速度はRequestsより遅くなりますが、より複雑なウェブサイトに対応できます。
特徴 | Requests | BeautifulSoup | Selenium |
---|---|---|---|
主な役割 | 静的コンテンツの取得 | HTML/XMLの解析・データ抽出 | ブラウザ操作の自動化・動的コンテンツ取得 |
得意なウェブサイト | JavaScriptなしのシンプルなサイト | 取得済みHTMLの構造解析 | JavaScript利用・ログイン・クリックなど複雑な操作があるサイト |
処理速度 | 高速 | HTML解析は高速 | やや遅い(実際のブラウザ起動のため) |
必要となる要素 | HTTPリクエストの知識 | HTML/XMLの構造知識、セレクタの知識 | ブラウザドライバー、ウェブ開発者ツール |

どのライブラリを使えばいいのか、毎回迷ってしまうのはなぜだろう?

ウェブサイトの動きに合わせて最適なツールを選ぶのが、データ収集の効率を最大化する秘訣です。
これら3つのツールそれぞれの特性を理解し、ウェブサイトの挙動を見極めて使い分けることで、あなたはあらゆるタイプのウェブサイトから必要な情報を、より確実に、そして効率良く抽出できるようになるでしょう。
5ステップでPythonスクレイピングを習得!Selenium実践ガイド
重要なのは、PythonのSeleniumを使えば、動的なウェブサイトからのデータ抽出も怖くない、という最強のスキルが手に入る点です。
環境準備からスタートし、基本操作、重要機能、そして高度なテクニックを習得、最終的に実用的なデータ活用まで、Pythonを使ったSeleniumスクレイピングの全てをマスターできる5つのステップを順に解説します。
これらのステップを一つずつ実践すれば、あなたのデータ収集業務は格段に効率的になるでしょう。
ステップ1 環境準備 SeleniumとWebDriverのセットアップ
Seleniumを使ったウェブスクレイピングを始める上で最も重要なのは、正確な環境準備です。
ここでいう「Selenium」はウェブブラウザを自動操作する強力なライブラリを指し、「WebDriver」はその命令を各ブラウザに伝えるための通訳のようなプログラムを意味します。
最初に「pip install selenium」でPythonのライブラリをインストールし、次に使用するウェブブラウザ(例えばGoogle Chrome)のバージョンに合わせた専用のChromeDriverをダウンロードしてパスを設定する作業が必要です。
わたしも初めてSeleniumを使うとき、WebDriverのバージョン違いで何時間も悩んだ経験がありますが、たった一つのバージョン不一致が大きなエラーに繋がることがあります。
必要なツールを正確に設定する手順は以下のとおりです。
手順 | 詳細 |
---|---|
Seleniumのインストール | コマンドプロンプトで pip install selenium を実行 |
WebDriverのダウンロード | Google Chromeのバージョンに合わせてChromeDriverを公式サイトからダウンロード(例: Chrome 120にはChromeDriver 120を) |
WebDriverの配置 | ダウンロードした chromedriver.exe をPythonスクリプトと同じフォルダか、任意のパス(例: C:\drivers )に配置 |

あれ、WebDriverってブラウザごとに違うんでしたっけ?ちゃんと合わせないと動かないんですかね?

そうです、WebDriverは使うブラウザの種類だけでなく、そのブラウザのバージョンにも厳密に合わせる必要があるんです
このステップで確実な基盤を築くことが、これからのスクレイピング成功の鍵を握っています。
ステップ2 基本操作 ブラウザ制御と要素の特定
Seleniumの真骨頂は、まるであなたが手で操作するように、ウェブブラウザをプログラムで制御できる点にあります。
「要素の特定」とは、ウェブページ上のテキストボックス、ボタン、画像など、操作したい一つ一つの部品を見つけ出す作業のことで、driver.get()
で特定のURLを開き、find_element_by_id()
やfind_element_by_css_selector()
などのメソッドを使って要素を特定し、send_keys()
でテキストを入力したり、click()
でボタンを押したりします。
主な要素検索メソッドをまとめたものです。
メソッド | 検索対象 |
---|---|
find_element_by_id | ID属性 |
find_element_by_name | Name属性 |
find_element_by_class_name | Class属性 |
find_element_by_tag_name | タグ名 |
find_element_by_xpath | XPath |
find_element_by_css_selector | CSSセレクタ |
特にJavaScriptによって後から読み込まれるコンテンツを取得するには、目的の要素が完全に表示されるまで数秒から10秒程度の「待機処理」を組み込むのが非常に重要で、待機処理を適切に行わないと「要素が見つかりません」といったエラーに頻繁に遭遇することになります。

ウェブページの要素を特定するのって、どれを使えば一番確実なんですか?毎回Chromeの開発者ツールで確認しないといけないのかな?

一番確実なのはCSSセレクタ、より複雑な場合はXpathを使うとよしなにことが進みます。
要素の特定は、基本的に開発者ツールで確認するのが一般的。開発者ツールの使い方をマスターすれば、多くのウェブサイトから効率的にデータを収集できるようになります。
ステップ3 重要機能 ログイン自動化と複数ページ遷移
Seleniumがデータサイエンティストにとって「重要機能」と呼ばれるゆえんは、ログインが必要なサイトや複数のページにわたる複雑な情報も自動で収集できることにあるでしょう。
これまでのRequestsとBeautifulSoupだけでは難しかった課題を、Seleniumはスマートに解決してくれます。
例えば、あなたの勤める会社のBIツールへのログインを自動化して毎日特定のレポートをダウンロードしたり、ウェブサイトの「次へ」ボタンを自動でクリックして数千ページにわたる顧客レビューを抽出するといった業務も実現できます。
seleniumで使える機能のおもな活用方法は以下のとおりです。
機能名 | 具体的な操作方法 | 利用シーン |
---|---|---|
ログイン自動化 | 入力欄を特定し、send_keys() で情報入力、click() でログインボタン押下 | ログインが必要なサイトからのデータ抽出、APIのないサービスの利用 |
複数ページ遷移 | 「次へ」ボタンのclick() 、またはURL規則性を利用したdriver.get() | ページングされたニュースサイト、製品リストからの全情報取得 |
ヘッドレスモード | ブラウザの画面表示なしでバックグラウンド実行 | サーバーでの実行、高速化、PC負荷軽減 |

ヘッドレスモードって、本当に画面が表示されないんですか?ちゃんと動いてるのか確認するのに不安になりますね…

ヘッドレスモードでは画面は表示されませんが、ログ出力やスクリーンショット機能で内部的な動作状況を確認することができます
ヘッドレスモードはテスト環境のときはオフにしておき、目視でちゃんと期待通りの動作をすることを確認してからヘッドレスモードをオンにされることをおすすめします。
これらの機能を活用することで、あなたのデータ収集業務の幅は格段に広がり、自動化による恩恵を最大限に受け取ることができるはずです。
ステップ4 高度なテクニック スクロールと外部ライブラリ連携
無限スクロールや特定の情報を効率よく抽出するためには、Seleniumの「高度なテクニック」である画面スクロールの自動化や、他のPythonライブラリとの連携が不可欠です。
たとえば、InstagramやAmazonのようなスクロールするたびにコンテンツが表示されるサイトでは、ページを最下部までスクロールする処理を自動で繰り返すことで、全ての投稿データを漏らさず取得できます。
さらに、Seleniumで取得したHTML情報を「BeautifulSoup」に渡せば、複雑なタグ構造の中から必要なデータ(例: 商品名、価格)を効率的に解析できますし、「Requests」ライブラリを使えば、ウェブスクレイピングで見つけた画像のURLを直接ダウンロードし、ローカルに保存することも可能です。
以下に他のライブラリとの連携の役割を示します。
連携ライブラリ | 主な役割 | 具体的な使用例 |
---|---|---|
BeautifulSoup | HTMLソースコードの効率的な解析 | Seleniumで取得したHTMLから特定要素の抽出(例: 価格、レビューテキスト) |
Requests | ファイルや画像データの直接ダウンロード | 画像のURLからPCへの自動保存、PDFファイルの収集 |

他のライブラリと連携するのって、コードが複雑になりそう…何かメリットはあるんですか?

はい、Seleniumでブラウザ操作を完結させ、他のライブラリでデータ解析やダウンロードを分担することで、コードの可読性が上がり、処理も効率化できるメリットがあります
高速な処理ではなくなる反面、seleniumと他のライブラリーを組み合わせることでBS+Requestsではできなかったスクレイピング処理が実現できます。
ステップ5 実用的なデータ活用 CSVファイルへの保存
これまで収集した膨大なデータを単なる情報の羅列で終わらせず、「実用的なデータ活用」へと繋げるための最終ステップが、CSVファイルへの保存です。
データをCSV形式で出力することで、ExcelやBIツール、さらにはPandasやNumPyといったPythonのデータ分析ライブラリで簡単に扱うことが可能になります。
Pythonの標準ライブラリであるcsv
モジュールを使えば、スクレイピングで取得したタイトルやURL、価格といった様々な種類のデータを約10行程度のコードで整然とした表形式で保存できます。
ファイル名を日付で自動生成したり、エンコーディングエラー(文字化け)を回避するencoding='utf-8'
やerrors='ignore'
を指定する工夫も忘れずに取り入れましょう。
CSVファイルへの保存手順は以下のとおりです。
ステップ | 詳細 |
---|---|
csv モジュールのインポート | import csv をコードの冒頭に追加 |
ファイルを開く | with open('ファイル名.csv', 'w', encoding='utf-8', newline='') as f: と記述 |
csv.writer オブジェクトの作成 | writer = csv.writer(f) を使用 |
データの書き込み | writer.writerow([データ1, データ2, ...]) で各行を書き込み |

CSVに保存した後、そのデータをどう活用するんですか?ただ保存するだけじゃなくて、もっといい方法があるんですかね?

保存したCSVデータは、高度なデータ分析や機械学習モデルの構築に利用できますよ。
今回はCSVに保存して活用することを例に挙げましたが、実務的には取得したデータを整形してメールでレポーティングしたり、SQL DBなどに保存して再利用したりとさまざまです。
次によく遭遇するエラーと解消方法について見ていきましょう。
Pythonスクレイピング Seleniumでエラー遭遇時!トラブル解決術

エラーを解決するのに時間がかかって疲れた。

私自身も遭遇したエラーと解決方法を紹介します。
PythonでのSeleniumスクレイピングは非常に強力なツールですが、残念ながら一発できれいにコードをアウトプットするのはまれで以下のようなエラーの壁を何度もトライアンドエラーを繰り返すのが一般的です。
- 要素が見つからないNoSuchElementException
- WebDriverとブラウザのバージョン不一致
- ウェブサイトからのブロック
上記の主要なエラーとその解決方法についてそれぞれ見ていきましょう。さらに、「堅牢なプログラムのための例外処理」を実装する方法も詳しく紹介します。
要素が見つからない時の対処法 NoSuchElementException
「NoSuchElementException」とは、Seleniumが指定されたウェブページ上で目的の要素を見つけられなかったときに発生するエラーです。
また以下のようにStacktrace
をログに出力することもあります。
- ERROR - 処理中に予期せぬエラーが発生しました: Message:
Stacktrace:
#0 0x5c043598301a <unknown>
#1 0x5c0435422a70 <unknown>
#2 0x5c0435474907 <unknown>
#3 0x5c0435474b01 <unknown>
#4 0x5c04354c2d54 <unknown>
#5 0x5c043549a40d <unknown>
#6 0x5c04354c014f <unknown>
#7 0x5c043549a1b3 <unknown>
#8 0x5c043546659b <unknown>
#9 0x5c0435467971 <unknown>
#10 0x5c04359481eb <unknown>
#11 0x5c043594bf39 <unknown>
#12 0x5c043592f2c9 <unknown>
#13 0x5c043594cae8 <unknown>
#14 0x5c0435913baf <unknown>
#15 0x5c04359700a8 <unknown>
#16 0x5c0435970286 <unknown>
#17 0x5c0435981ff6 <unknown>
#18 0x7e172a867ac3 <unknown>

どうすればウェブページ上の要素を正確に見つけられるの?

適切な待機処理と正確なセレクタ指定が鍵を握ります。
遷移するページが複数になる場合、そもそもユーザー側の期待した通りのページ遷移ではないケースや広告や認証クッキーバナーが挟まることもよくあるため、以下の点に配慮するのがおすすめです。
- どのようなページ遷移をするのか?
- スマホやPCで出現要素やページ構成が変化しないか?
- プライベートモードでアクセスしてクッキーバナーや広告がはさまらないか?
検証には、DevツールのElementsタブを使ってHTML構造を正確に理解することで、エラーは解決できます。
上記の確認が済んだら、以下のような点にも注意が必要です。
原因 | 対策 |
---|---|
読み込み遅延 | 明示的待機(WebDriverWait)を使用して要素の出現を待つ |
セレクタの誤り | デベロッパーツールのElementsタブでHTML構造を確認し、CSSセレクタやXPathを正確に指定する |
フレーム内の要素 | iframe内の要素であれば、driver.switch_to.frame()でフレームに切り替える |
WebDriverとブラウザのバージョン不一致対策
WebDriverとは、Seleniumがブラウザを自動操作するための「仲介役」のようなもので、ブラウザとWebDriverは、それぞれバージョンが厳密に一致している必要があります。
Google Chromeの場合、以下のコードのように自動的に更新する記述をしてあれば問題ありませんが、ローカル環境でスクレイピングをしている場合、下記のように記述しても更新されないことがあります。
from selenium import webdriver
# この行を実行するだけで、Selenium Managerが
# 自動的に適切なChromeDriverをダウンロードまたは更新します。
driver = webdriver.Chrome()
# これ以降の処理
driver.get("https://www.google.com")
print(driver.title)
driver.quit()
わたしも過去にブラウザが自動更新された後にエラーの沼にハマったことがあり、以下のコードで手動アップデートをしたことが何度とあります。
# seleniumをアップデートするコマンド
pip install --upgrade selenium
しかし、ローカル環境で動かしている場合、手動アップデートでもchromeDriverが更新されないことがあるので、以下のリンクから最新版のChromeDriverを手動でダウンロードして置き換えることをおすすめします。
参考:最新版Chromeダウンロード先
問題 | 確認方法 | 解決策 |
---|---|---|
バージョン | Google Chromeの設定 -> Chromeについて でブラウザバージョンを確認 | 該当するバージョンのChromeDriverをダウンロードし、既存のファイルを置き換える |
エラー表示 | 実行時エラーメッセージ(例: SessionNotCreatedException)に注目 | 自動でWebDriverを更新するライブラリ(例: webdriver-manager)の導入を検討する |
使用しているブラウザのバージョンに合わせたWebDriverを常に最新の状態に保つことで、安定した動作を確保できます。
ウェブサイトからのブロック回避と効果的な対策
ウェブサイトからの「ブロック」とは、スクレイピングがウェブサイトのサーバーに過度な負荷をかけたり、不審なアクセスと判断されたりした場合にサーバー側のシステム判定または手動でブロックされ、IPアドレスを一時的または永久にアクセス禁止にされることです。
例えば、短時間に何百回、何千回とリクエストを送るとほぼ確実にブロックされますし、海外からのアクセスをそもそもブロックする機能を備えているサーバーもあります。

ブロックされないためにはどうしたらいいの?

適切な間隔とランダム性を加えることが効果的です
対策の種類 | 具体例と理由 |
---|---|
待機時間の導入 | time.sleep() を使って1〜5秒程度のランダムな遅延を設ける |
User-Agent変更 | 人間のブラウザのようにUser-Agentを定期的に変更する |
プロキシ利用 | 複数のIPアドレスを使い、同一IPからの集中アクセスを避ける |
ヘッドレスモードの注意 | 不必要な場合は通常のブラウザ表示で実行することも検討する(ヘッドレスモードが検出される場合があるため) |
上記の対策を組み合わせることで、ウェブサイトからのブロックリスクを大幅に減らし、安定したスクレイピング実行が可能です。
プロキシ利用については、有料・無料どちらも使用できるプロキシがあるので、予算や利用目的に応じて検討してみるのがおすすめです。興味があれば、筑波大学で研究されている無料VPN「VPN Gate」を参考にするのも良いかと。
堅牢なPythonプログラムのための例外処理
「例外処理」とは、プログラムの実行中に発生するエラー(例外)を予測し、適切に対応するための仕組みです。
Pythonではtry-except
構文がこれにあたります。
ウェブスクレイピングでは、ネットワークの瞬断や予期せぬウェブサイトの変更・長期間スクレイピングによるメモリ不足など、20以上の多様な例外が発生する可能性があります。

エラーの種類によって処理を変える必要はあるの?

特定の例外に対応した処理と予期せぬ例外に備える処理を組み合わせるのが理想的です。
ポイント | 説明と効果 |
---|---|
try-except 構文 | try ブロック内で通常処理を実行し、except ブロックで例外を捕捉し、エラーに応じた回復処理を実行する |
エラーログ出力 | どの部分で、どのようなエラーが発生したかを記録するロギング機能を導入する |
リトライ処理 | 一時的なネットワークエラーなどに対し、一定時間待ってから再度処理を試みるロジックを実装する |
finally ブロック | try ブロックの結果に関わらず、必ず実行したいクリーンアップ処理(例: ブラウザを閉じる)を記述する |
例外処理を適切に組み込むことで、エラー発生時にもプログラムが途中で停止せず、より安定して信頼性の高いスクレイピングツールを構築できます。
【実践】Seleniumを使ってPython公式サイトをスクレイピングしてみる

実際にSeleniumを使ってスクレイピングしてみましょう。

待ってました。
- サイト名:Python公式サイト
- サイトURL:https://www.python.org/
- 利用規約:https://www.python.org/about/legal/
- robots.txt:https://www.python.org/robots.txt
Pythonの公式サイトをサンプルとして使わせていただき、実際にスクレイピングをしてみましょう。
- robots.txt・利用規約を確認する
- 取得する要素を確認する
- スクリプトを書き、検証する
各スクレイピング手順について、それぞれ見ていきましょう。
実践手順1. robots.txt・利用規約を確認する
まずは、スクレイピングが可能かどうか利用規約とrobots.txtを確認します。
# Directions for robots. See this URL:
# http://www.robotstxt.org/robotstxt.html
# for a description of the file format.
User-agent: HTTrack
User-agent: puf
User-agent: MSIECrawler
Disallow: /
# The Krugle web crawler (though based on Nutch) is OK.
User-agent: Krugle
Allow: /
Disallow: /~guido/orlijn/
Disallow: /webstats/
# No one should be crawling us with Nutch.
User-agent: Nutch
Disallow: /
# Hide old versions of the documentation and various large sets of files.
User-agent: *
Disallow: /~guido/orlijn/
Disallow: /webstats/
以上のrobots.txtと利用規約から以下のことが読み取れます。
- /~guido/orlijn/ と /webstats/ はスクレイピング禁止
- 以下の名前を持つクローラーはすべてのページへアクセス拒否
HTTrack, puf, MSIECrawler, Nutch - 利用規約に明示的なスクレイピング禁止は記載されていない
特定のページを除けば、常識の範囲内でスクレイピングができることが確認できます。
実践手順2. 取得する要素を確認する
今回はPythonでSeleniumを使用してスクレイピングするということなので、Pythonの公式サイトから投稿されている記事のタイトルと投稿日を取得していく流れは、以下のとおりです。
- Python公式サイトにアクセスする
- Newsのナビメニューをクリックする
- 新着記事一覧からmoreをクリックする
- 記事一覧の投稿日と記事タイトルを取得する
- CSVに保存してダウンロードする
要素を確認する際に注意しておきたいのがPCとスマホやモバイルなどの端末による見え方やページ遷移先が異なる場合があります。(今回はその典型例)


Seleniumでスクレイピングをする際は、PCのブラウザーからアクセスすることになるので、開発者ツールをそのつど閉じてからページ遷移させることが必要です。

いちいち開発者ツールを閉じるの面倒くさい。

PCとモバイルで取得要素の名称自体が変わることもあるので、面倒でも開発者ツールを閉じましょう。
実践手順3. Pythonスクリプトを書き、検証する
今回は、ウェブスクレイピングをすることが目的であるため、開発環境に関しては言及しません。したがって、誰でもほぼ同じ動作環境が再現できるGoogle Colaboratory(通称:Colab)でコードの実装を行います。
Python公式にアクセスして新着ニュースを取得するコードは下記の通り。
# 必要なライブラリをインストールします
# Google Colab環境の場合はpipの前に!を付けるのがお作法です
!pip install selenium
!pip install webdriver-manager
# ==============================================================================
# セクション1: 環境構築(Google Colab環境で実行)
# ==============================================================================
import logging
import os
import sys
# 意図したフォーマットでログ出力する
for handler in logging.root.handlers[:]:
logging.root.removeHandler(handler)
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
# Google Colab環境であるかを判定
IS_COLAB = "google.colab" in sys.modules
try:
if IS_COLAB:
logging.info(">>> Google Colab環境を検出しました。環境構築を開始します。")
# Chromeのインストール
if not os.path.exists("/usr/bin/google-chrome-stable"):
get_ipython().system('apt-get update -qq && apt-get install -y wget gnupg google-chrome-stable -qq')
# 必要なPythonライブラリのインストール
get_ipython().system('pip install selenium webdriver-manager pandas beautifulsoup4 lxml -q')
logging.info(">>> 環境構築が正常に完了しました。")
else:
logging.info(">>> ローカル環境とみなし、環境構築をスキップします。")
except Exception as e:
logging.error(f"--- 環境構築中にエラーが発生しました: {e} ---")
raise SystemExit("環境構築に失敗したため、処理を中断します。")
# ==============================================================================
# セクション2: ライブラリのインポート
# ==============================================================================
import time
import pandas as pd
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# Colabでファイルをダウンロードするために必要
if IS_COLAB:
from google.colab import files
# --- WebDriverのセットアップ ---
options = Options()
options.add_argument('--headless') # ブラウザを画面に表示しないモード
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument('--disable-gpu')
options.add_argument('--window-size=1920,1080')
options.add_argument('user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.102 Safari/537.36')
# ユーザーエージェントをPCに指定し、モバイルサイトへの意図しないリダイレクトを防ぐ
service = Service(ChromeDriverManager().install())
driver = None
# ==============================================================================
# セクション3: メイン処理
# ==============================================================================
try:
# 1. WebDriverのインスタンスを生成
driver = webdriver.Chrome(service=service, options=options)
logging.info("WebDriverのセットアップが完了しました。")
# 待機時間設定 (最大30秒)
wait = WebDriverWait(driver, 30)
# 2. https://www.python.org/ にアクセスする
driver.get("https://www.python.org/")
logging.info(f"'{driver.title}' にアクセスしました。")
# 3. ニュースをクリックする
logging.info("「News」リンクをクリックします...")
# 要素がクリックされるのを防ぐオーバーレイなどを回避するため、JavaScriptでクリック
news_link_locator = (By.XPATH, '//*[@id="news"]/a')
news_link_element = wait.until(EC.presence_of_element_located(news_link_locator))
driver.execute_script("arguments[0].click();", news_link_element)
# 4. https://www.python.org/blogs/ にページ遷移したことを確認
wait.until(EC.url_contains('/blogs/'))
logging.info(f"ニュース一覧ページ ({driver.current_url}) に遷移しました。")
# 5. "more" をクリックする
logging.info("「more」リンクをクリックします...")
more_link_locator = (By.XPATH, '//*[@id="content"]/div/section/div/div[1]/div/p/a')
more_link_element = wait.until(EC.element_to_be_clickable(more_link_locator))
driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", more_link_element) # 要素を画面中央に表示
time.sleep(1) # スクロール待機
more_link_element.click()
# 6. https://blog.python.org/ または https://pythoninsider.blogspot.com/ に遷移するのを待つ
wait.until(
lambda d: 'blog.python.org' in d.current_url or 'pythoninsider.blogspot.com' in d.current_url
)
logging.info(f"ブログサイト ({driver.current_url}) に正常に遷移しました。")
# サイトの種類(PC版かモバイル版か)を判定
is_mobile_site = 'pythoninsider.blogspot.com' in driver.current_url
if is_mobile_site:
logging.info(">>> モバイル版ブログサイトのスクレイピングを開始します。")
else:
logging.info(">>> PC版ブログサイトのスクレイピングを開始します。")
# 7. ブログの記事タイトルおよび投稿日を取得する
news_data = []
MAX_PAGES = 10 # 最大10ページまで取得
for i in range(MAX_PAGES):
logging.info(f"--- ページ {i + 1} のデータを取得します ---")
# 記事コンテナが表示されるまで待機
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, ".blog-posts")))
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
page_articles_found = 0
# PCサイトとモバイルサイトで構造が異なるため、処理を分岐
if is_mobile_site:
# --- モバイルサイトのスクレイピングロジック ---
# 日付ごとにグループ化されているコンテナを取得
post_containers = soup.select(".blog-posts > div.date-posts")
for container in post_containers:
date_tag = container.select_one("div.date-header span")
date = date_tag.get_text(strip=True) if date_tag else "日付不明"
# コンテナ内の記事をすべて取得
articles = container.select("div.mobile-post-outer")
for article in articles:
title_tag = article.select_one("a > h3.post-title")
if title_tag:
title = title_tag.get_text(strip=True)
# 重複がないかチェックしてリストに追加
if title and not any(d['タイトル'] == title for d in news_data):
logging.info(f" >> 発見: [投稿日: {date}] [タイトル: {title}]")
news_data.append({'投稿日': date, 'タイトル': title})
page_articles_found += 1
else:
# --- PCサイトのスクレイピングロジック ---
# 日付ごとにグループ化されているコンテナを取得
post_containers = soup.select(".blog-posts > div.date-outer")
for container in post_containers:
date_tag = container.select_one("h2.date-header span")
date = date_tag.get_text(strip=True) if date_tag else "日付不明"
# コンテナ内の記事をすべて取得
articles = container.select("div.post-outer")
for article in articles:
title_tag = article.select_one("h3.post-title a")
if title_tag:
title = title_tag.get_text(strip=True)
# 重複がないかチェックしてリストに追加
if title and not any(d['タイトル'] == title for d in news_data):
logging.info(f" >> 発見: [投稿日: {date}] [タイトル: {title}]")
news_data.append({'投稿日': date, 'タイトル': title})
page_articles_found += 1
logging.info(f"このページから新たに {page_articles_found} 件の記事を取得しました。")
# 新しい記事が1件もなければ、最終ページとみなしてループを抜ける
if page_articles_found == 0 and i > 0:
logging.info("新たな記事がなかったため、最終ページと判断し、処理を終了します。")
break
# 次のページへ遷移 (最後のページでなければ)
if i < MAX_PAGES - 1:
try:
# サイトによって「次のページ」ボタンのセレクタが違う
if is_mobile_site:
next_button_locator = (By.ID, "blog-pager-older-link")
else:
next_button_locator = (By.CSS_SELECTOR, "a.older-posts")
# ボタンをクリックして次ページへ
older_posts_button = driver.find_element(*next_button_locator)
older_posts_button.click()
logging.info(f"次のページ({i + 2}ページ目)へ遷移します...")
time.sleep(2) # ページ遷移と読み込みのための待機
except Exception:
logging.info("「Older Posts」ボタンが見つかりませんでした。ここで取得を終了します。")
break
logging.info(f"合計 {len(news_data)} 件のニュースを取得しました。")
# 8. CSVファイルに投稿日、記事タイトルをCSVファイルに出力し、ダウンロードする
if news_data:
df = pd.DataFrame(news_data, columns=['投稿日', 'タイトル'])
csv_filename = 'python_blog_news.csv'
df.to_csv(csv_filename, index=False, encoding='utf-8-sig')
logging.info(f"取得したデータを'{csv_filename}'に保存しました。")
# Google Colab環境の場合、ファイルをダウンロード
if IS_COLAB:
files.download(csv_filename)
logging.info("ファイルのダウンロードが開始されました。")
else:
logging.warning("取得できたニュースがなかったため、CSVファイルは作成されませんでした。")
except Exception as e:
logging.error(f"処理中に予期せぬエラーが発生しました: {e}", exc_info=True)
if driver:
# エラー発生時のスクリーンショットを保存
error_filename = 'error_screenshot.png'
driver.save_screenshot(error_filename)
logging.info(f"エラー発生時のスクリーンショットを '{error_filename}' として保存しました。")
if IS_COLAB:
files.download(error_filename)
finally:
if driver:
driver.quit()
logging.info("WebDriverを終了しました。")
エラーやクラッシュを防ぐためのTRY
処理の補足説明
実行したいメインの処理を確実に実行するためにtry: の中にメイン処理を書きます。
ウェブスクレイピングは、以下のような様々な理由で失敗する可能性があります。
- ネットワークの問題: インターネット接続が不安定、またはサイトが一時的にダウンしている。
- サイトの仕様変更: 昨日まで存在したボタンのIDやクラス名が、今日になったら変更されている。
- タイミングの問題: ページの読み込みが遅く、探している要素がまだ表示されていない。
- 予期せぬポップアップ: 広告やクッキーの同意画面が表示され、クリックしたい要素を覆い隠してしまう。
上記の問題が起きると、Seleniumは「要素が見つかりません (NoSuchElementException)」などのエラー(例外)を発生させます。tryブロックがない場合、このエラーが発生した瞬間にプログラムは停止し、赤いエラーメッセージを大量に表示して終了してしまいます。
tryブロック内でエラーが発生すると、プログラムは即座にexceptブロックにジャンプします。これは、プログラムがクラッシュするのを防ぐセーフティネットの役割を果たします。
exceptブロックでは、以下のような「後処理」を行います。
- エラーの記録: logging.error()を使って、どんなエラー(e)が起きたのかを記録します。これにより、後から「なぜ失敗したのか」を調査する手がかりになります。
- 証拠保全: driver.save_screenshot()でエラー発生時の画面を画像として保存します。「サイトのレイアウトが変わっていた」「広告が表示されていた」など、視覚的に原因を特定するのに非常に役立ちます。
- ユーザーへの通知: ユーザーに「エラーが発生しました」と親切に伝えることができます。
exceptがないと、ただクラッシュするだけで、何が原因だったのか分からずじまいになってしまいます。
finallyブロックは、tryブロックの処理が成功しようが、exceptブロックでエラーが捕捉されようが、必ず最後に実行されるという非常に重要なブロックです。
今回のコードで最も重要な役割は driver.quit() の実行です。
- webdriver.Chrome() で起動したブラウザは、Pythonスクリプトとは別のプロセスとして動いています。
- もしスクリプトがエラーで終了したり、正常に終了した場合でも、driver.quit() を呼び出さないと、ブラウザのプロセスがメモリ内に残り続けてしまいます。
- これが何度も繰り返されると、PCのメモリやCPUをどんどん消費し、動作が重くなる原因になります(ゾンビプロセス)。
finallyブロックに driver.quit() を書いておくことで、どんな状況でも確実にブラウザを閉じてリソースを解放することが保証されます。
上記のコードのようにtry….except….finallyとすることでクラッシュを防ぎ、安定的に動作させるコードの鉄則とも言える作法です。

except(エラー処理)の組み立て方が重要です。
参考までに以下のリンクにGoogle Colabのサンプルコードを置いておくので参考にしてください。
参考:Google Colab