Playwright で Scraper Proxy を使う:住宅プロキシの認証・セッション・再試行・データ検証
Python と Playwright によるプロキシ接続を解説。HTTP 認証、住宅プロキシのスティッキーセッション、429 Retry-After、通信量の最適化、データ検証を公式資料とコードで紹介します。
プロキシを接続して出口 IP が変わったのに、価格が別の地域のままなのはなぜでしょうか。HTTP 200 が返っても有効な商品データを保存できない、画像をブロックしても通信量が減らない、といった問題もあります。
原因を調べる層はそれぞれ異なります。ネットワーク出口、ブラウザーの状態、ページの準備完了条件、データの受け入れ判定です。本番用の scraper proxy 接続では、プロキシセッションとブラウザーコンテキストを一緒に管理し、業務データで成功を判定します。 Python、Playwright、BifrostNetwork を使って具体的に説明します。
資料確認日:2026 年 9 月 14 日。公式ドキュメントとプロトコル標準に基づく記事です。コードは接続と検証の例であり、商用プロキシの成功率、遅延、削減率を実測したものではありません。
1. プロキシが担当する範囲を決める
Scraper proxy は、クローラーが対象サイトへ接続するときのネットワーク出口です。Proxy scraper は通常、プロキシアドレスを収集するツールを指し、別の用途です。
この構成では、キューが実行時刻を決め、Playwright が JavaScript を実行し、ゲートウェイが出口を選び、パーサーが項目を抽出し、検証処理が保存可否を決めます。プロキシはセレクターの保守やアクセス権の付与を代行しません。
| タスクの条件 | 検討の出発点 | 確認する項目 |
|---|---|---|
| 公式 API やエクスポートに必要な項目がある | そのインターフェースを優先 | 上限、データ利用権限、更新頻度 |
| HTML に必要なデータが揃っている | HTTP クライアント。必要ならプロキシを追加 | 解析精度、出口の要件 |
| JavaScript や操作が必要 | タスク単位のプロキシを設定した Playwright | 準備完了条件、状態、ブラウザー資源 |
| 特定市場の住宅回線からの観測が必要 | 住宅出口で試験 | 実際の国、ページの市場、セッション継続性 |
これは設計上の提案であり、住宅プロキシの性能優位を示す結果ではありません。費用の比較は Scraper Proxy 選定ガイドを参照してください。
Playwright はブラウザー起動時と BrowserContext 単位のプロキシ設定に対応します。独立したコンテキスト間では Cookie とキャッシュを共有しないため、タスクの分離に利用できます。ネットワーク設定、Browser.new_context。
2. まずプロトコルと認証を確認する
Chromium の SOCKS5 対応にはパスワード認証が含まれない
Chromium の公式資料では、Chrome の SOCKSv5 は認証方式に対応していないと明記されています。requests で使える認証付き SOCKS5 接続文字列を Playwright Chromium にそのまま渡すと失敗する場合があります。本記事ではユーザー名とパスワード付きの HTTP プロキシを使用します。Chromium の実装説明。
proxy.username と proxy.password はプロキシ認証、http_credentials は対象サイトの HTTP 認証です。プロキシの認証情報をサイト認証に入れたり、Proxy-Authorization を通常のページリクエストヘッダーとして送ったりしないでください。Playwright の認証・プロキシ設定。
プロキシ URL が http:// でも、接続先は HTTPS にできます。HTTP プロキシが CONNECT トンネルを作り、その中で接続先との TLS 通信を行います。ただし、クライアントからプロキシまでの外側の接続も TLS になるわけではありません。その区間の認証情報を暗号化するには、事業者とクライアントの双方が明示的に対応する HTTPS プロキシエンドポイントを使用します。URL の接頭辞を変えるだけでは不十分です。RFC 9110:CONNECT、Chromium の HTTP/HTTPS プロキシ。
認証情報をコピーし、ユーザー名にルーティング条件を追加する
BifrostNetwork の現行資料には、gate.bifrostnetwork.cc:9521 と HTTP/HTTPS CONNECT 対応が記載されています。ユーザー名に国、セッション ID、TTL を付加できます。基本ユーザー名は注文情報からコピーし、例からプランコードを推測しないでください。接続ドキュメント。
基本ユーザー名-country-us-session-一意なタスクID-ttl-300
-country-us は米国出口、-session-… はスティッキーセッション、-ttl-300 は 300 秒を指定します。TTL 省略時の文書上の既定値は 600 秒です。未対応の地域・ASN の組み合わせではフォールバックがあるため、ユーザー名だけで実際の国を判断できません。セッションと地域指定。
3. 一つの業務フローに一つのコンテキストとセッションを割り当てる
商品一覧 → 市場選択 → 詳細を開く → 価格取得は、状態を持つ一連の処理です。タスク ID に以下を関連付けます。
task_id
├─ country + proxy_session_id
├─ BrowserContext(Cookie、サイトストレージ、locale)
└─ 開始・終了時刻 + 内容検証結果
処理終了時にコンテキストを閉じ、次の独立タスクでは新しいセッション ID を作ります。同じページのナビゲーション、スクリプト、XHR の途中でプロキシ設定を切り替えたり、前の市場の Cookie を保持したまま出口だけを変えたりしないようにします。
これはタスクの分離方針であり、新しいセッションに未使用の IP が必ず割り当てられる保証ではありません。接続の再利用、利用可能なノード、ルーティングに結果が左右されます。出口確認を一度行っても、その後の全サブリクエストが同じノードを通る証明にはなりません。長い処理では要所で出口の変化を確認し、予定セッション時間を超えるタスクは再スケジュールします。
IP の国、ブラウザーの locale、配送先の国、通貨は別々に検証します。locale="en-US" は言語関連の挙動に影響しますが、出口 IP を米国にしたり、サイトの市場選択を代替したりはしません。locale の設定。
4. Python の例:キューを拡張する前に一ページを検証する
分離した Python 環境に Playwright と対応する Chromium をインストールします。本番では Python、Playwright、ブラウザーのバージョンを記録・固定し、回帰確認を再現可能にします。インストール手順。
python -m pip install playwright
python -m playwright install chromium
実行前に環境変数またはシークレット管理サービスから次の値を渡します。パスワードはリポジトリや共有のシェル履歴に保存しないでください。
| 変数 | 内容 |
|---|---|
BIFROST_BASE_USERNAME | 管理画面の基本ユーザー名。以下で追加するルーティング条件を含めない |
BIFROST_PASSWORD | プロキシのパスワード |
TARGET_URL | 収集が許可されていることを確認済みの HTTPS ページ |
READY_SELECTOR | 業務上の要素一つに一致する CSS セレクター |
EXPECTED_TEXT | その要素に含まれるべき空でない文字列 |
BIFROST_PROXY_SERVER | 任意。既定値は http://gate.bifrostnetwork.cc:9521 |
scraper_proxy.py として保存し、python scraper_proxy.py で実行します。一回のページアクセスだけを行い、認証・HTTP・内容検証エラーは上位のスケジューラーへ渡します。暗黙の IP 切り替えや再試行は行いません。
import asyncio
import json
import os
import time
import uuid
from urllib.parse import urlsplit
from playwright.async_api import async_playwright, expect
async def main():
target = os.environ["TARGET_URL"]
selector = os.environ["READY_SELECTOR"]
expected = os.environ["EXPECTED_TEXT"].strip()
parsed = urlsplit(target)
if parsed.scheme != "https" or not parsed.hostname or not expected:
raise ValueError("有効な HTTPS URL と空でない期待文字列が必要です")
task_id = uuid.uuid4().hex[:16]
base = os.environ["BIFROST_BASE_USERNAME"]
proxy = {
"server": os.environ.get(
"BIFROST_PROXY_SERVER", "http://gate.bifrostnetwork.cc:9521"
),
"username": f"{base}-country-us-session-{task_id}-ttl-300",
"password": os.environ["BIFROST_PASSWORD"],
}
async with async_playwright() as p:
browser = await p.chromium.launch(headless=True)
try:
context = await browser.new_context(proxy=proxy, locale="en-US")
try:
page = await context.new_page()
started = time.monotonic()
response = await page.goto(
target, wait_until="domcontentloaded", timeout=30_000
)
if response is None:
raise RuntimeError("ナビゲーションでメインドキュメントの応答が返りませんでした")
if not 200 <= response.status < 300:
# 上位のスケジューラーで記録・解析します。ここで即座に再試行しません。
raise RuntimeError(json.dumps({
"task_id": task_id,
"status": response.status,
"retry_after": response.headers.get("retry-after"),
}))
ready = page.locator(selector)
await expect(ready).to_have_count(1, timeout=10_000)
await expect(ready).to_be_visible(timeout=10_000)
await expect(ready).to_contain_text(expected, timeout=10_000)
print(json.dumps({
"task_id": task_id,
"status": response.status,
"elapsed_ms": round((time.monotonic() - started) * 1000),
"content_check": "passed",
}))
finally:
await context.close()
finally:
await browser.close()
if __name__ == "__main__":
asyncio.run(main())
セレクターと期待する文字列は対象ページに合わせます。全 EC サイトで使える共通セレクターはありません。本番では最終 URL、商品 ID、価格、通貨、市場、取得時刻も検証し、業務キーで重複を除去します。この例は明確に失敗できる準備完了条件のみを示します。空のセレクター、複数一致、タイムアウトをすべてプロキシ障害と判断してはいけません。Locator assertions はタイムアウトまで条件を繰り返し確認します。Locator assertions。
page.goto() は 404 や 500 などの有効な HTTP ステータスで自動的に例外を投げないため、レスポンスを確認します。返るのはメインドキュメントの応答であり、その後の商品 API の成功を意味しません。domcontentloaded は DOM イベントの発火で、データ準備完了には別の検証が必要です。公式資料で非推奨の networkidle をデータ完全性の代わりに使わないでください。Page.goto。
5. 原因別に再試行する:429 で即座に IP を変えない
| 現象 | 最初に調べること | スケジューラーの対応 |
|---|---|---|
| 407 またはプロキシ認証例外 | ユーザー名、パスワード、プロトコル、プラン | その設定を停止し、認証情報を修正 |
| CONNECT 失敗・接続タイムアウト | ゲートウェイ到達性、プロトコル、出口と対象の接続 | 層別に調査し、一時障害と確認できたら限定的に再試行 |
| 401 / 403 | 対象の認証、アクセス方針、応答内容 | アクセス条件を確認し、無限再試行を避ける |
| 429 | レート制限と適用範囲 | Retry-After を解析し、該当処理の負荷を下げる |
| 502 / 503 / 504 | ゲートウェイ由来か対象由来か、一時的か | 発生元の手掛かりを記録し、予算内で待機 |
| 200 だが項目欠損・地域不一致 | 状態、データ API、解析、市場設定 | 内容検証失敗とし、修正後に再実行 |
401、403、407 は、それぞれ対象の認証、処理の拒否、プロキシ認証に関するステータスです。ブラウザーのトンネル確立失敗はページ応答ではなく例外になる場合があります。RFC 9110 のステータス定義。
RFC 6585 は IP だけを基準に数えることを要求していません。アカウント、Cookie、リソースに制限が紐付くこともあります。429 後の IP 変更で制限が解消するとは限らず、システム全体の対象への負荷も制御できません。RFC 6585 第 4 節。
Retry-After は非負整数の秒数か HTTP 日付です。両方を解析し、日付は現在の UTC との差から待機時間を計算して時計のずれも考慮します。RFC 9110:Retry-After。
対象のルールとタスク予算に応じ、再試行を制限します。
解析可能な Retry-After なし:ランダムな揺らぎを加えた指数バックオフ
有効な Retry-After あり:指定時間以上待ち、小さな揺らぎを加える
待機が残り予算を超える:延期または終了。待機時間を短縮しない
試行上限に到達:エラー分類を残して失敗キューへ送る
少なくとも対象ドメイン単位でレートを集計し、アカウント枠がある場合はドメインをまたいで予算を共有します。worker 間で待機状態を共有しないと、各 worker の並行数が少なくても合計は上限を超えます。一回のナビゲーションがスクリプト、画像、API を呼ぶため、ページタスク数と HTTP リクエスト数は異なります。
Scrapy の現行 RetryMiddleware は既定の再試行対象に 429 を含みますが、それだけでサーバー指定の待機方針が完成するわけではありません。AutoThrottle は遅延を参照し、高速な非 200 応答によって待機を短縮しない仕組みです。実際の設定で待機と再試行を確認してください。RetryMiddleware、AutoThrottle。
6. 通信量は通常読み込みを測ってから最適化する
不要な画像・動画はありますが、HTML 以外をすべてブロックするとページを壊します。通常読み込みを基準として記録し、不要と確認できた資源だけを試験的に止め、項目の完全性、処理時間、課金対象の通信量を比較します。
context.route() を有効にすると HTTP キャッシュが無効になります。また、Service Worker が処理するリクエストはそのインターセプトを通らない場合があります。公式資料は service_workers="block" の検討を推奨していますが、Service Worker 依存のページの挙動が変わります。複数ページ間でキャッシュを再利用していた処理では、導入後に総費用を測り直します。BrowserContext.route。
完了後の request.sizes() で大きな資源を調べられます。responseBodySize はエンコード後の本文バイト数です。プロキシ請求量そのものではなく、プロトコルのオーバーヘッド、失敗リクエスト、事業者の計量範囲は別途確認が必要です。Request.sizes。
len(page.content()) は描画後の HTML 文字列の長さであり、全通信バイト数や全ページ資源の大きさではありません。
7. 固定サンプルで BifrostNetwork を評価する
主要テンプレートと市場を含む URL 群を選び、ブラウザーバージョン、時間帯、タスク数、再試行予算、項目ルールを揃えます。サンプル数はページの多様性と変動に応じて決めます。以下は評価方法であり、サービス性能の保証ではありません。
| 指標 | 記録方法 | 分かること |
|---|---|---|
| 出口と市場の整合性 | 実際の IP、位置判定元、ページの国と通貨 | 対象市場のデータか |
| 内容検証の合格率 | 合格タスク数 ÷ 全タスク数 | HTTP 成功を超えて使える割合 |
| セッションの変化 | 要所の出口とサイト状態 | 長い処理で条件を維持できるか |
| 遅延分布 | 成功の P50/P95、失敗・タイムアウトは別記 | 取得期限を満たせるか |
| 再試行による増加 | 全試行数 ÷ タスク数 | 不安定さで増えた作業量 |
| 有効 1,000 件当たりの費用 | 総費用 ÷ 合格・重複除去後の件数 × 1,000 | 規模に見合う費用か |
総費用にはプロキシ料金、ブラウザー計算資源、帰属可能な保守費を含めます。有効データがゼロなら単価は計算不能で、その試験は不合格です。プランは同じ条件で比較し、最高の一回を平均として扱わないでください。
既存の Playwright パイプラインには proxy 設定で BifrostNetwork を組み込みます。管理画面の認証情報と開発者資料の国・セッション指定を使い、現在の料金と試験請求量から予算を算出してください。本記事は未測定のスループットを示さず、動的住宅スティッキーセッションを専用静的 IP の SLA ともみなしません。
本番前に対象の API、アクセスルール、頻度制限を確認します。robots.txt はクローラー向けルールであり、RFC 9309 はアクセス許可そのものではないと明記しています。例は robots ルールを自動取得・適用しないため、タスク受付時に処理してください。RFC 9309。
よくある質問
米国プロキシなのに別の通貨が表示されるのはなぜですか?
実際の出口、配送先、Cookie、アカウントの市場、返されたデータを確認します。IP の国は条件の一つです。BifrostNetwork の文書にあるルーティングのフォールバックも検証に含めます。
リクエストごとに IP を変えると安定しますか?
関連するナビゲーションと XHR の途中で出口を変えると、状態不整合の原因を追いにくくなります。業務タスクをセッションの区切りにし、独立した次のタスクで必要ならコンテキストとセッションを新しくします。
HTTP 200 だけで成功と判断できないのはなぜですか?
メインドキュメントが空の枠組みだけだったり、API が失敗したり、ログイン画面やエラーだったりします。項目、市場、時刻、重複除去をすべて通過したデータを数えます。
すぐに数百タスクの同時実行へ拡張できますか?
まず一タスクのブラウザー資源と対象負荷を測り、上限付きキュー、共有待機、失敗予算を追加します。並行数はシステム容量の制約であり、worker を増やしても対象の許容アクセス頻度は変わりません。