DrissionPageとは — HTTPとブラウザを統合するPythonフレームワーク
Pythonでスクレイピングを行う開発者の多くは、requestsライブラリとSeleniumやPlaywrightを併用している。シンプルなHTTPリクエストで済むページにはrequestsを使い、JavaScriptレンダリングが必要なページにはブラウザを起動する——この切り替えは、Cookieの共有、セッション管理、コードの重複という観点で大きな手間を生む。
DrissionPageは、この問題を解決するPythonフレームワークだ。HTTPリクエストモード(SessionPage)とChromiumブラウザ制御モード(ChromiumPage)を1つのオブジェクトで切り替え可能にし、状態(Cookie、ヘッダー)を共有したまま両方のモードを使える。DrissionPageプロキシの設定も各モードで統一的に行えるため、IPローテーションを伴うDrissionPage web scrapingのワークフローが大幅にシンプルになる。
DrissionPageのGitHubリポジトリで公開されており、Chromium DevTools Protocol(CDP)を基盤としてWebDriverに依存しない軽量なブラウザ制御を実現している。本記事はDrissionPage tutorialとして、プロキシ統合に焦点を当てた実践的なガイドを提供する。
法的・倫理的注意事項:公開データの収集のみを行い、対象サイトの利用規約(ToS)と
robots.txtを尊重すること。米国のCFAAやEUのGDPRはスクレイピング行為に法的制約を課す場合がある。可能な場合は公式APIの利用を優先すること。
DrissionPageの3つのページモデル
DrissionPageのコアは3つのページクラスにある。それぞれの役割と、なぜコスト削減につながるのかを理解することが、DrissionPageを使いこなす第一歩だ。
SessionPage — requests風のHTTPクライアント
SessionPageはrequestsライクなAPIでHTTPリクエストを送る。ブラウザを起動しないため、リクエストのオーバーヘッドは約200ms以内に収まり、メモリ消費も最小限だ。静的なHTMLページやJSON APIの取得に最適。
ChromiumPage — CDP駆動のブラウザ制御
ChromiumPageはChromium DevTools Protocolを通じて実際のブラウザを制御する。WebDriverを使わずCDPに直接接続するため、Selenium比で起動が速く、JavaScriptレンダリング、XHRのインターセプト、スクリーンショット取得などが可能。DrissionPage Chromiumモードは、SPA(シングルページアプリケーション)や動的にコンテンツを生成するサイトに不可欠。
WebPage — モード切り替えと状態共有
WebPageはSessionPageとChromiumPageの両方を内包し、page.change_mode()で切り替えが可能。切り替え時もCookieやヘッダーが引き継がれるため、HTTPモードでログイン処理を行い、ブラウザモードでJSレンダリング後のページを取得する——といったワークフローがシームレスに実現できる。
| 特徴 | SessionPage | ChromiumPage | WebPage |
|---|---|---|---|
| HTTPリクエスト | 対応 | — | 対応(切り替え可能) |
| JSレンダリング | — | 対応 | 対応(切り替え可能) |
| Cookie共有 | 独立 | 独立 | 対応(モード間で共有) |
| XHRインターセプト | — | 対応(listen) | 対応(ブラウザモード時) |
| メモリ使用量 | 低(約50MB) | 高(約300MB) | モード依存 |
| プロキシ設定 | set_proxies() | ChromiumOptions.set_proxy() | 両方 |
常にブラウザを起動するSeleniumやPlaywrightと違い、DrissionPageでは「まずHTTPで取得を試み、必要な場合のみブラウザに切り替える」という段階的なアプローチが取れる。これにより、ブラウザの起動コスト(プロセス起動+初期化で約2〜5秒、メモリ約300MB)を、本当に必要な場合にのみ支払うことができる。
DrissionPageのAPI — ele/eles、ChromiumOptions、listen
DrissionPageのAPIは直感的で、jQuery風のロケーターとイベントリスニングを組み合わせた設計になっている。ここでは実践でよく使う3つの機能を解説する。
ele() / eles() — 要素の特定
要素の検索にはele()(単一要素)とeles()(複数要素)を使う。CSSセレクター、XPath、タグ名、属性など柔軟な指定が可能。
from DrissionPage import WebPage
page = WebPage()
page.get('https://example.com')
# CSSクラスで検索
title = page.ele('@class=title')
# タグ + 属性で検索
button = page.ele('tag:input@type=submit')
# XPathで検索
items = page.eles('xpath://div[@class="item"]/a')
# テキスト内容で検索
link = page.ele('text:詳細を見る')ChromiumOptions — ブラウザの設定
ChromiumOptionsでブラウザの起動オプションを制御する。ヘッドレスモード、ユーザーエージェント、プロキシ、ウィンドウサイズなどを設定できる。
from DrissionPage import ChromiumOptions
co = ChromiumOptions()
co.set_argument('--headless=new')
co.set_user_agent('Mozilla/5.0 (Windows NT 10.0; Win64; x64)')
co.set_proxy('http://user-country-US:pass@gate.proxyhat.com:8080')
co.set_argument('--window-size=1920,1080')listen.start() — バックグラウンドXHRのキャプチャ
DrissionPageの強力な機能の1つが、ネットワークパケットのリスニングだ。listen.start()で特定のURLパターンを監視し、バックグラウンドで発生するXHR/Fetchリクエストのレスポンスを直接取得できる。これにより、SPAの裏で動いている非公開APIを発見し、ブラウザを経由せずに直接HTTPで叩ける場合がある。
page = WebPage(mode='chromium')
# XHRの監視を開始
page.listen.start('api.example.com/data')
# ページ上でアクションを実行
page.ele('tag:button@text()=もっと見る').click()
# キャプチャしたレスポンスを取得
packet = page.listen.wait(timeout=10)
if packet:
print(packet.response.body) # JSONデータ
print(packet.url) # エンドポイントURLDrissionPageプロキシの設定 — SessionPageとChromiumPage
DrissionPageでプロキシを使う場合、モードによって設定方法が異なる。しかし、どちらのモードでもProxyHatのゲートウェイを透過的に利用できる。
SessionPageのプロキシ設定
SessionPageではset_proxies()メソッドを使う。標準的なrequestsと同じ辞書形式で指定する。
from DrissionPage import SessionPage
page = SessionPage()
page.set_proxies({
'http': 'http://user-country-US:pass@gate.proxyhat.com:8080',
'https': 'http://user-country-US:pass@gate.proxyhat.com:8080'
})
page.get('https://httpbin.org/ip')
print(page.json)ChromiumPageのプロキシ設定
ブラウザモードではChromiumOptionsのset_proxy()を使う。Chromium起動時にプロキシが適用される。
from DrissionPage import ChromiumPage, ChromiumOptions
co = ChromiumOptions()
co.set_proxy('http://user-country-US:pass@gate.proxyhat.com:8080')
co.set_argument('--headless=new')
page = ChromiumPage(co)
page.get('https://httpbin.org/ip')
print(page.ele('tag:pre').text)なぜレジデンシャルプロキシが必要なのか
データセンタープロキシは高速だが、IPレピュテーションが低く、多くのサイトでブロックされる。SERPトラッキング、eコマース価格監視、ソーシャルメディア調査などの「ハードターゲット」では、本物のISPに割り当てられたレジデンシャルIPが必要だ。ProxyHatのレジデンシャルプロキシは、実際の住宅回線からのIPを提供し、データセンタープロキシ比でブロック率を大幅に下げる。詳細はProxyHatのロケーション一覧を参照。
実践例 — WebPageでHTTPからブラウザへ
ここでは、WebPageを使ってHTTPモードで開始し、JSレンダリングが必要なページでChromiumモードに切り替える実践的な例を示す。ProxyHatのレジデンシャルエンドポイントを通じて、米国IPでセッションを固定しながらアクセスする。
from DrissionPage import WebPage, ChromiumOptions
import json, uuid
# ProxyHatのユーザー名をビルド
def build_username(country='US', session=None):
parts = [f'country-{country}']
if session:
parts.append(f'session-{session}')
return '-'.join(parts)
USERNAME = build_username(country='US', session=uuid.uuid4().hex[:8])
PASSWORD = 'your_password'
PROXY_HTTP = f'http://{USERNAME}:{PASSWORD}@gate.proxyhat.com:8080'
# WebPageをHTTPモードで初期化
page = WebPage(mode='session')
page.set_proxies({
'http': PROXY_HTTP,
'https': PROXY_HTTP,
})
# Step 1: HTTPモードでAPIエンドポイントを叩く
resp = page.get('https://api.example.com/products?page=1')
if resp and page.status_code == 200:
data = page.json
items = data.get('items', [])
print(f'HTTPモード: {len(items)}件取得')
# Step 2: JSレンダリングが必要なページに切り替え
co = ChromiumOptions()
co.set_proxy(PROXY_HTTP)
co.set_argument('--headless=new')
# ブラウザモードに切り替え(プロキシを引き継ぎ)
page.change_mode(mode='chromium', go=False, co=co)
# ブラウザモードでページを取得
page.get('https://example.com/dashboard')
# XHRをリスニングして裏APIを発見
page.listen.start('api.example.com/analytics')
page.ele('tag:button@text()=読み込み').click()
packet = page.listen.wait(timeout=15)
if packet:
print(f'発見したAPI: {packet.url}')
body = packet.response.body
print(f'レスポンス: {json.dumps(body, indent=2)[:500]}')この例のポイントは、HTTPモードとブラウザモードで同じプロキシエンドポイントを使い、セッションID(session-abc123)でIPを固定していることだ。これにより、モードを切り替えても同じIPアドレスからアクセスしているように見え、セッションの一貫性が保たれる。
ProxyHatの料金体系や利用可能なプロキシタイプについては、ProxyHatの料金ページを参照。また、Webスクレイピング全般のユースケースはWebスクレイピングのユースケースで詳しく解説している。
本番運用パターン — セッション固定、リトライ、並行処理
DrissionPageを本番環境で使う場合、いくつかの重要なパターンを押さえておく必要がある。
セッション単位のプロキシ固定
ログイン後のセッションを維持するには、同じIPを使い続ける必要がある。ProxyHatではユーザー名にsession-{id}を含めることで、スティッキーセッションを実現できる。セッションIDが同じ限り、同じIPが割り当てられる。
import uuid
# 各スクレイピングセッションに固有のIDを割り当て
session_id = uuid.uuid4().hex[:8]
username = f'user-country-US-session-{session_id}'
# このセッション中は同じIPが使われる
proxy = f'http://{username}:pass@gate.proxyhat.com:8080'リトライとバックオフ
ネットワークエラーや一時的なブロックに対処するため、指数バックオフ付きのリトライを実装する。最大3回のリトライ、初回1秒、2回目2秒、3回目4秒の待機が実用的な基準だ。
import time
from DrissionPage import SessionPage
def fetch_with_retry(page, url, max_retries=3):
for attempt in range(max_retries):
try:
resp = page.get(url, timeout=15)
if resp and page.status_code == 200:
return page
elif page.status_code == 429:
wait = 2 ** attempt # 1s, 2s, 4s
print(f'Rate limited. {wait}s待機...')
time.sleep(wait)
else:
print(f'Status {page.status_code}, リトライ {attempt + 1}')
time.sleep(2 ** attempt)
except Exception as e:
print(f'エラー: {e}, リトライ {attempt + 1}')
time.sleep(2 ** attempt)
return Noneパケットキャプチャで非公開APIを発見
DrissionPageのlisten機能を使うと、ブラウザがバックグラウンドで叩いているAPIエンドポイントを発見できる。一度エンドポイントを見つければ、SessionPage(HTTPモード)で直接叩ける場合があり、ブラウザの起動コストを省略できる。これはSERPトラッキング(SERPトラッキングのユースケース参照)で特に有用だ。多くのSPAは初期ロード時にバックグラウンドでJSON APIを叩いており、listen.start()でそのURLとレスポンス構造を把握すれば、以降はHTTPモードで高速にデータ取得できる。
並行処理と同時接続の制限
DrissionPageを並行実行する場合、同時接続数を制御することが重要だ。レジデンシャルプロキシでは、100並行セッションが実用的な上限の目安。それ以上はIPプールの枯渇や対象サイトのレート制限に抵触する可能性がある。
from concurrent.futures import ThreadPoolExecutor, as_completed
import uuid
from DrissionPage import SessionPage
def scrape_page(url, country='US'):
session_id = uuid.uuid4().hex[:8]
proxy = f'http://user-country-{country}-session-{session_id}:pass@gate.proxyhat.com:8080'
page = SessionPage()
page.set_proxies({'http': proxy, 'https': proxy})
page.get(url, timeout=15)
result = page.ele('tag:h1').text if page.status_code == 200 else None
page.close()
return result
urls = [
'https://example.com/page1',
'https://example.com/page2',
'https://example.com/page3',
]
# 最大10並行で実行
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(scrape_page, url) for url in urls]
for future in as_completed(futures):
print(future.result())並行処理では、各スレッドに固有のセッションIDを割り当てることが重要だ。これにより、各スレッドが異なるIPアドレスを使用し、単一IPへの負荷集中を防げる。
ブラウザを使うべきでないケースと倫理
DrissionPageの強みは「必要な時だけブラウザを使える」ことだ。しかし、すべてのページでブラウザを起動するのは非効率であり、対象サイトにも余計な負荷をかける。以下の基準で判断する。
HTTPモード(SessionPage)で十分なケース
- 静的HTMLページ(サーバーサイドレンダリング)
- JSON API(エンドポイントが分かっている場合)
- XMLサイトマップやrobots.txtの取得
- 認証不要の公開ページ
ブラウザモード(ChromiumPage)が必要なケース
- JavaScriptでコンテンツが動的生成されるSPA
- CloudflareやAkamaiなどのボット対策が実装されているページ
- ログイン後にJSでトークンが生成されるサイト
- XHR/FetchのパケットをキャプチャしてAPIを発見したい場合
倫理的ガイドライン
スクレイピングは強力なツールだが、責任を持って使う必要がある。以下の原則を守ること:
- 公開データのみを対象とする:ログイン背後のデータや、意図的に非公開にされているデータは収集しない。
- robots.txtを尊重する:
robots.txtでクロールが禁止されているパスにはアクセスしない。 - レート制限を守る:1秒あたり1〜2リクエスト程度に抑え、対象サイトのサーバーに過度な負荷をかけない。
- 公式APIを優先:対象サイトが公式APIを提供している場合は、スクレイピングよりAPIの利用を優先する。
- データの取り扱いに注意:個人情報(PII)の収集はGDPRやCCPAなどの規制に準拠する必要がある。詳細はGDPR公式サイトを参照。
米国ではCFAA(Computer Fraud and Abuse Act)が、意図しないアクセスや過度なスクレイピングに対して法的制約を課す。常に最新の法的解釈を確認すること。
Key Takeaways
- DrissionPageはHTTPとブラウザを1つのツールで統合:SessionPage、ChromiumPage、WebPageを使い分け、必要な時だけブラウザのコストを支払う。HTTPモードのオーバーヘッドは約200ms、ブラウザモードは起動に約2〜5秒かかる。
- プロキシはモード別に設定:SessionPageは
set_proxies()、ChromiumPageはChromiumOptions.set_proxy()で設定。ProxyHatのgate.proxyhat.com:8080を両方で使える。 - レジデンシャルプロキシでブロックを回避:ハードターゲットにはデータセンターよりレジデンシャルIPが有効。セッションIDでIPを固定可能。
- listen機能でAPIを発見:ブラウザモードでXHRをキャプチャし、見つけたAPIをHTTPモードで直接叩くことで効率化。
- 並行処理は100セッション上限が目安:各スレッドに固有のセッションIDを割り当て、IP分散とレート制限を両立する。
- 倫理と法令を遵守:公開データのみ、robots.txt尊重、レート制限を守り、公式APIを優先する。
ProxyHatのレジデンシャルプロキシを使えば、DrissionPageの強力な機能を最大限に活用できる。ProxyHatのドキュメントで詳細な設定方法を確認し、料金プランから自分のユースケースに合ったプランを選択しよう。






