モダンなWebアプリケーションの多くは、ページを遷移せずにバックグラウンドでAPI通信を行い、動的にコンテンツを更新する仕組みを採用しています。
従来のSeleniumによるスクレイピング手法では、ブラウザ上に表示されたHTML要素(DOM)を解析することが一般的でした。
しかし、SPA(シングルページアプリケーション)の普及に伴い、表面上のHTMLだけでは取得できない重要なデータがネットワーク通信の中に隠されているケースが増えています。
そこで注目されているのが、Chrome DevTools Protocol(CDP)を活用したネットワークリクエストの監視です。
本記事では、PythonとSeleniumを組み合わせてブラウザ内部の通信をキャッチし、効率的にデータを取得する最新の手法を詳しく解説します。
なぜDOM解析だけではなくネットワーク監視が必要なのか
Webサイトの構造が複雑化する中で、DOM要素のみをターゲットにしたスクレイピングには限界が生じています。
多くのサイトではJavaScriptによって非同期にJSONデータを取得し、それを基に画面をレンダリングしています。
このようなサイトで特定の情報を抽出する場合、描画された後のテキストを取得するよりも、大元のAPIレスポンスを直接キャッチする方が確実かつ高速です。
また、広告の読み込み状況や画像などのバイナリデータのURL、リクエストヘッダーに含まれる認証トークンなどは、通常のDOM操作では容易に取得できません。
ネットワークリクエストを監視することで、ブラウザがサーバーとどのようなやり取りをしているのかを完全に可視化できます。
これにより、スクレイピングの安定性が向上し、より高度なデータ収集が可能になります。
Chrome DevTools Protocol(CDP)の基礎知識
CDPは、Google ChromeやMicrosoft EdgeなどのChromiumベースのブラウザを制御・デバッグするための低レベルなプロトコルです。
開発者ツールの「ネットワーク」タブや「コンソール」タブで確認できる情報は、すべてこのプロトコルを介して提供されています。
Selenium 4以降、このCDPとの連携機能が強化されており、execute_cdp_cmdというメソッドを通じてブラウザの内部機能に直接アクセスできるようになりました。
CDPには「Domain(ドメイン)」と呼ばれる機能単位が存在し、ネットワーク監視には主に「Network」ドメインを使用します。
これを利用することで、リクエストが送信される直前のタイミングや、レスポンスが返ってきた瞬間のイベントをフックできます。
PythonとSeleniumによる環境構築
ネットワーク監視を実装するためには、適切なバージョンのライブラリとドライバが必要です。
2026年現在の標準的な環境では、Python 3.10以上とSelenium 4.x系の組み合わせが推奨されます。
まずは必要なパッケージをインストールまたは更新しましょう。
pip install selenium webdriver-manager
webdriver-managerを利用することで、ブラウザのバージョンに合わせたドライバーの管理が自動化され、メンテナンスコストを削減できます。
CDPを使用したネットワーク監視の基本実装
SeleniumでCDPを有効化し、実際にネットワークイベントを購読する手順を解説します。
まずは、ブラウザを起動し、Network.enableコマンドを送信してネットワークドメインを有効にします。
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import json
# ChromeOptionsの設定
options = webdriver.ChromeOptions()
# ヘッドレスモードが必要な場合は有効にする
# options.add_argument('--headless')
# ドライバの初期化
driver = webdriver.Chrome(service=Service(ChromeDriverManager().install()), options=options)
# CDPのNetworkドメインを有効化する
driver.execute_cdp_cmd('Network.enable', {})
# イベントをキャッチした際の処理(ここでは単純に出力)
def print_request_log(event):
print(f"Request: {event['request']['url']}")
# ページ遷移
driver.get("https://example.com")
この基本的なコードでは、Networkドメインを有効にしただけで、まだイベントの待ち受け(リスナー)が設定されていません。
次に、具体的なイベントタイプを指定してデータを取得する方法を見ていきましょう。
主要なネットワークイベントの種類
CDPで監視できるネットワークイベントには、主に以下の3つがあります。
| イベント名 | 発生タイミング | 取得できる主な情報 |
|---|---|---|
| Network.requestWillBeSent | リクエスト送信時 | URL、メソッド、リクエストヘッダー |
| Network.responseReceived | レスポンス受信時 | ステータスコード、レスポンスヘッダー、MIMEタイプ |
| Network.loadingFinished | データ読み込み完了時 | リクエストID、データサイズ |
動的なネットワークログをキャプチャする実践コード
実際に特定のURL(例えばAPIエンドポイント)へのリクエストを特定し、その詳細をログに記録するコードを実装します。
Seleniumのexecute_cdp_cmdだけではイベントの連続的な監視が難しいため、ブラウザのログ機能を併用する手法が一般的です。
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import time
# ログ取得を有効にするための設定
caps = DesiredCapabilities.CHROME.copy()
caps['goog:loggingPrefs'] = {'performance': 'ALL'}
options = webdriver.ChromeOptions()
options.set_capability('goog:loggingPrefs', {'performance': 'ALL'})
driver = webdriver.Chrome(options=options)
# ターゲットサイトへアクセス
driver.get("https://www.google.com")
# ネットワークログを抽出する関数
def get_network_logs(driver):
# performanceログを取得
logs = driver.get_log('performance')
network_events = []
for entry in logs:
log = json.loads(entry['message'])['message']
# Network.responseReceivedイベントのみを抽出
if log['method'] == 'Network.responseReceived':
network_events.append(log)
return network_events
# 少し待機して通信を発生させる
time.sleep(3)
# ログの解析
events = get_network_logs(driver)
for event in events:
url = event['params']['response']['url']
status = event['params']['response']['status']
print(f"URL: {url} | Status: {status}")
driver.quit()
URL: https://www.google.com/ | Status: 200
URL: https://www.gstatic.com/og/_/js/k=og.qtm.en_US.v... | Status: 200
URL: https://apis.google.com/_/scs/abc-static/_/js/... | Status: 200
このように、performanceログを解析することで、ブラウザ内部で行われたすべての通信をプログラムから追跡可能になります。
レスポンスボディ(中身)を取得する高度なテクニック
ステータスコードやURLだけでなく、APIから返ってきたJSONデータの中身(レスポンスボディ)を直接取得したい場合があります。
これを行うには、Network.getResponseBodyというCDPコマンドを使用します。
このコマンドにはリクエストごとに割り振られるrequestIdを渡す必要があります。
# リクエストIDを指定してボディを取得
request_id = event['params']['requestId']
try:
body = driver.execute_cdp_cmd('Network.getResponseBody', {'requestId': request_id})
print(f"Body: {body['body'][:100]}...") # 最初の100文字を表示
except Exception as e:
# 画像やストリーミングデータなど取得できない場合はエラーになるためハンドリングが必要
pass
この手法を駆使すれば、画面をスクレイピングすることなく、バックグラウンドでやり取りされる生のデータを直接データベースに保存するといった処理も可能になります。
Selenium-wireとの比較
ネットワーク監視を行うためのライブラリとして「Selenium-wire」というサードパーティ製ライブラリも有名です。
CDPを直接操作する方法と、Selenium-wireを使用する方法のどちらを選択すべきか、以下の比較を参考にしてください。
| 特徴 | CDP(ネイティブ)直接操作 | Selenium-wire |
|---|---|---|
| 依存関係 | 標準のSeleniumのみで完結 | 追加ライブラリが必要 |
| 仕組み | ブラウザのデバッグポートを利用 | プロキシサーバーを介在させる |
| パフォーマンス | 非常に高速 | プロキシ経由のため、ややオーバーヘッドがある |
| 導入難易度 | CDPの知識が必要でやや複雑 | Pythonのリスト操作感覚で非常に容易 |
| 認証プロキシ | 設定が難しい | 容易に設定可能 |
実行速度やモダンなブラウザ機能への追従性を重視する場合は、ネイティブなCDP操作が圧倒的に有利です。
一方で、手軽に短期間で実装を終わらせたい場合は、Selenium-wireも有力な選択肢となります。
ネットワーク監視を実装する際の注意点
CDPを活用した監視は非常に強力ですが、いくつか注意すべきポイントがあります。
第一に、メモリ使用量の増大です。
すべてのネットワークログをキャプチャし続けると、長時間稼働させるスクレーパーではメモリを大量に消費します。
必要なドメイン(例:XHRのみ)に絞って監視を行うか、定期的にログをクリアする設計にしてください。
第二に、セキュリティとプライバシーです。
ネットワークリクエストにはCookieや認証トークン、個人情報が含まれることが多々あります。
取得したデータをログファイルに出力する際は、機密情報が含まれていないか十分に精査してください。
第三に、ブラウザのバージョン依存です。
CDPはブラウザの内部仕様に依存しているため、Chromeのメジャーアップデートにより挙動が変わる可能性があります。
定期的にSeleniumやドライバーを最新の状態に保つことが、安定運用の鍵となります。
実用的なフィルタリングの実装方法
大量のリクエストの中から、特定のデータだけを効率的に抽出するためのフィルタリング手法を紹介します。
例えば、拡張子が「.json」のもの、あるいはURLに「/api/v1/」が含まれるものだけを対象にするコードは以下の通りです。
def is_target_api(url):
targets = ["/api/v1/user", "/api/v1/order"]
return any(target in url for target in targets)
# 取得したイベントをループ
for event in events:
url = event['params']['response']['url']
if is_target_api(url):
# ターゲットとなる通信が見つかった場合の処理
handle_api_data(event)
このように、監視対象を絞り込むことで、解析の負荷を大幅に軽減し、スクリプトの実行速度を維持できます。
トラブルシューティング:ログが表示されない場合
CDPの設定をしているにもかかわらず、期待したログが取得できないことがあります。
その場合、まずはgoog:loggingPrefsが正しく設定されているかを確認してください。
また、ブラウザが完全に読み込みを完了する前にスクリプトが終了していないか、適切な待機時間(Explicit Wait)が設けられているかも重要です。
ヘッドレスモードを使用している場合、一部のネットワークイベントが通常モードと異なる挙動をすることもあります。
デバッグの際は一度ヘッドレスを解除し、実際にブラウザの挙動を目視で確認することをお勧めします。
まとめ
本記事では、SeleniumとChrome DevTools Protocol(CDP)を連携させ、ネットワークリクエストを監視する方法を解説しました。
CDPを活用することで、DOM解析だけでは到達できなかった深層のデータにアクセスできるようになります。
特に動的なWebサイトからのデータ収集において、この手法は非常に強力な武器となります。
パフォーマンスの最適化やメモリ管理に注意しつつ、今回紹介したコードをベースに、より高度なブラウザ自動化に挑戦してみてください。
最新のブラウザ技術を使いこなすことで、スクレイピングの可能性はさらに広がっていくはずです。
