Selenium と Playwright のプロキシ認証:動作するすべての手法(2026)

2026年6月4日公開 · 約10分で読めます

ブラウザ自動化の開発者なら誰もが必ず一度はハマる罠があります。Chrome の起動フラグに --proxy-server=http://user:pass@host:port を追加すると、ブラウザ自体は問題なく起動するのに、どのページも、スクリプトからは見ることもクリックすることもできない認証ポップアップで固まってしまうのです。Chrome はプロキシフラグから認証情報を黙って削ぎ落とします。エラーもログ行もなく、ただ誰も見ていないブラウザの中にモーダルダイアログが出るだけです。

本稿は、2026 年に Selenium と Playwright で実際に動作するプロキシ認証手法の完全な見取り図です — どれを使うべきか、どれを避けるべきか、そしてそれぞれの正確なコードを示します。(これらのツールでのプロキシ選択とローテーション戦略については、Playwright & Puppeteer でプロキシを使うを参照してください — 本稿は純粋に「認証情報を通す」ことだけを扱います。)

なぜブラウザでは user:pass@host が失敗するのか

コマンドライン HTTP クライアントは、プロキシ URL から認証情報をパースし、プロキシの 407 Proxy Authentication Required に対して Proxy-Authorization ヘッダーで自動的に応答します。Chromium はそうしません。--proxy-serverscheme://host:port のみを受け付け、407 が返ってくるとインタラクティブなダイアログを表示します。ヘッドレスモードではダイアログすら出ず — リクエストはただ失敗します。

つまり問題は決して「どうやってパスワードを URL に入れるか」ではなく —「どの層が代わりに 407 に応答するか」です。動作する答えは 4 つ、良いものから順に紹介します。

手法 1: Playwright ネイティブ認証(使えるならこれを)

Playwright はこの問題を正しく解決しました。CDP 経由でプロキシ認証チャレンジに自前で応答します。認証情報は launch または context のオプションに渡します:

# Python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        proxy={
            "server": "http://us.jibaoproxy.com:913",
            "username": "USERNAME-session-job1",
            "password": "PASSWORD",
        }
    )
// Node.js - and per-context, which is where it gets powerful:
const browser = await chromium.launch({
  proxy: { server: 'per-context' }   // declare intent at launch
});
const ctx = await browser.newContext({
  proxy: {
    server: 'http://us.jibaoproxy.com:913',
    username: 'USERNAME-session-job2',
    password: 'PASSWORD',
  }
});

per-context プロキシは、1 つのブラウザプロセスで N 個の context を N 個の異なる sticky セッション上で動かせることを意味します — 本格的なあらゆる Playwright スクレイピング構成の基盤です。Playwright を使っているなら、これで完了です。検証セクションまで読み飛ばしてください。以下のすべては、Selenium に同等の機能がないために存在します。

手法 2: selenium-wire(Selenium、Python)

selenium-wire は、上流の認証を処理するローカル MITM プロキシで Selenium をラップします:

from seleniumwire import webdriver   # pip install selenium-wire

options = {
    "proxy": {
        "http":  "http://USERNAME:[email protected]:913",
        "https": "https://USERNAME:[email protected]:913",
    }
}
driver = webdriver.Chrome(seleniumwire_options=options)
driver.get("https://example.com")

本番投入前に知っておくべき注意点:

手法 3: 認証情報を注入する Chrome 拡張機能(Selenium、任意の言語)

古典的なアプローチ:プロキシを設定し、chrome.webRequest.onAuthRequired 経由で認証に応答する小さな生成済み拡張機能です。MITM も追加プロセスもなく、素の Selenium で動作します:

import zipfile, json

HOST, PORT = "us.jibaoproxy.com", 913
USER, PASS = "USERNAME-session-sel1", "PASSWORD"

manifest = {
    "version": "1.0.0", "manifest_version": 2, "name": "Proxy Auth",
    "permissions": ["proxy", "webRequest", "webRequestBlocking", ""],
    "background": {"scripts": ["background.js"]},
}
background = f"""
chrome.proxy.settings.set({{value: {{mode: "fixed_servers", rules: {{
  singleProxy: {{scheme: "http", host: "{HOST}", port: {PORT}}}
}}}}, scope: "regular"}}, () => {{}});
chrome.webRequest.onAuthRequired.addListener(
  () => ({{authCredentials: {{username: "{USER}", password: "{PASS}"}}}}),
  {{urls: [""]}}, ["blocking"]
);
"""

with zipfile.ZipFile("proxy_auth.zip", "w") as zp:
    zp.writestr("manifest.json", json.dumps(manifest))
    zp.writestr("background.js", background)

from selenium import webdriver
opts = webdriver.ChromeOptions()
opts.add_extension("proxy_auth.zip")
driver = webdriver.Chrome(options=opts)

落とし穴が 2 つ:拡張機能は従来のヘッドレスモードでは読み込まれません--headless=new(Chrome 109+)を使うか、ヘッド付きで実行してください。そして Manifest V2 のバックグラウンドスクリプトはサイドロードする自動化拡張機能では今も動作しますが、Chrome の MV2 廃止スケジュールには注意してください — MV3 版では service worker と同じ onAuthRequired リスナーが必要になります。

手法 4: ローカルフォワーダー(万能のフォールバック)

認証情報を保持する小さなローカルプロキシを動かし、ブラウザは認証なしで localhost に向けます。あらゆるブラウザ、あらゆるドライバー、あらゆる言語で、ヘッドレスかどうかを問わず動作します:

# Using pproxy (pip install pproxy) - terminal 1:
pproxy -l http://127.0.0.1:8899 \
       -r "http://USERNAME:[email protected]:913"

# Your script - terminal 2: plain Selenium, no auth needed
opts = webdriver.ChromeOptions()
opts.add_argument("--proxy-server=http://127.0.0.1:8899")
driver = webdriver.Chrome(options=opts)

これは Firefox/geckodriver(拡張機能のトリックが使えない)や、Electron アプリのテストのような特殊な環境にとっても最もクリーンな答えです。コスト:監督すべき可動部分がもう 1 つ増えること、そして per-context ルーティングにはセッションごとに 1 つのフォワーダーポートが必要になることです。

手法の比較

手法動作環境ヘッドレスper-context セッション本番での評価
Playwright ネイティブPlaywrightデフォルトの選択肢
selenium-wireSelenium (Py)ドライバー単位中規模なら問題なし
認証拡張機能Selenium(任意の言語)--headless=new のみドライバー単位堅実、MV3 に注意
ローカルフォワーダーすべてセッションごとに 1 ポート万能のフォールバック

実際に効いたか検証する

本物の IP へのサイレントなフォールバックこそ、アカウントを BAN させる失敗モードです。すべての実行の冒頭で出口 IP をアサートしてください:

ip = driver.execute_script(
    "return fetch('https://api.ipify.org').then(r => r.text())"
) if hasattr(driver, 'execute_script') else page.evaluate(
    "fetch('https://api.ipify.org').then(r => r.text())"
)
assert ip != MY_REAL_IP, "Proxy not applied - aborting before we leak"
無料ツール · 登録不要

自動化ブラウザを目視チェック

Selenium/Playwright のブラウザを当社の What Is My IP ページに誘導してください。出口 IP、ジオロケーション、ASN タイプ、proxy/VPN フラグを 1 画面で表示します — 認証層が効いて IP が residential であることを即座に確認できます。

IP チェッカーを開く →

「residential」のはずのプロキシで datacenter の ASN が見えますか?本当に residential なプールに切り替えましょう — 500MB の無料トラフィック →

トラブルシューティング クイックリファレンス

まとめ

ブラウザは user:pass@ 形式のプロキシ URL を読みません — 何かが代わりに 407 に応答しなければなりません。Playwright ではその「何か」が組み込まれています。Selenium では selenium-wire、生成した認証拡張機能、またはローカルフォワーダーです。比較表からあなたのスタックに合わせて選び、そして すべての実行で出口 IP をアサートしてください。そうすればサイレントな認証失敗がクロールの途中で本物のアドレスを漏らすことは決してありません。

今夜、4 つの手法すべてをテスト

500MB の無料トラフィック — 1 つのゲートウェイ、sticky もローテーションも、HTTP も SOCKS5 も。

無料トライアルを始める

すべてのIP製品に対応 · 膨大なノードプールをいつでも利用可能

今すぐ登録して、チャージ額の最大 100% をキャッシュバック

新規ユーザーは登録時に500MBを獲得、さらに初回チャージにボーナスが付きます。期間限定オファーです。