ブラウザ自動化フレームワークはすべてプロキシを起動オプションとして受け取りますが、認証付きプロキシは特別な処理が必要です。ChromiumはプロキシURL内のuser:pass@を受け付けないため、Playwrightは資格情報を別フィールドとして受け取り(ブラウザコンテキストごとに異なるプロキシを設定可能)、Puppeteerはpage.authenticate()が必要で、Seleniumは拡張機能またはローカルフォワーダーが必要です。 このガイドでは、それぞれの動作するコードを示し、その後、構文よりも重要な部分、つまり住宅用IPの背後にあるヘッドレスブラウザが、他の要素が一致しない限り識別可能であることについて説明します。
すべてを左右する事実:ChromiumはURL内のプロキシ資格情報を無視する
コマンドラインツールやPythonライブラリはhttp://user:pass@host:portを問題なく受け取ります。しかし、Chromiumの--proxy-serverフラグはhost:port(オプションでスキーム)のみを受け取り、資格情報は静かに破棄されます。プロキシが407で応答すると、ブラウザは認証ダイアログを表示しますが、自動化スクリプトはそれを監視していません。したがって、各フレームワークにはユーザー名とパスワードを提供する独自の方法があり、ここで「curlではプロキシが機能するのにブラウザスクリプトでは機能しない」という問題のほとんどが発生します。Firefoxは一部のパスでより寛容ですが、以下のフレームワーク固有のメカニズムはエンジン間で機能します。
Playwright
Playwrightは、資格情報を別フィールドとして持つファーストクラスのプロキシサポートを備えており、そして、マルチアイデンティティ作業に最適な機能である、プロキシをブラウザコンテキストごとに設定できるため、1つのブラウザプロセスで、それぞれ異なるIPからアクセスする複数の分離されたセッションをホストできます。
Python
from playwright.sync_api import sync_playwright
PROXY = {"server": "http://proxy.example.com:8080",
"username": "user", "password": "pass"}
with sync_playwright() as p:
# オプションA: ブラウザ全体に1つのプロキシ
browser = p.chromium.launch(proxy=PROXY)
page = browser.new_page()
page.goto("https://api.ipify.org?format=json")
print(page.text_content("body"))
browser.close()
# オプションB: コンテキストごとに異なるプロキシ(1つのブラウザで複数のアイデンティティ)
browser = p.chromium.launch(proxy={"server": "per-context"}) # プレースホルダー; 実際のプロキシはコンテキストから取得
ctx_de = browser.new_context(proxy={"server": "http://gate.provider.com:7777",
"username": "customer-country-de-session-a1", "password": "pass"},
locale="de-DE", timezone_id="Europe/Berlin")
ctx_us = browser.new_context(proxy={"server": "http://gate.provider.com:7777",
"username": "customer-country-us-session-b2", "password": "pass"},
locale="en-US", timezone_id="America/New_York")
for ctx in (ctx_de, ctx_us):
pg = ctx.new_page(); pg.goto("https://api.ipify.org?format=json"); print(pg.text_content("body"))
browser.close()
2つの詳細。Chromiumでコンテキストごとのプロキシを使用するには、ブラウザをプロキシオプション付きで起動する必要があります(任意の値—ドキュメント化されたプレースホルダーは{"server": "per-context"})。これがないと、コンテキストはプロキシを上書きできません。また、プロキシと一緒にlocaleとtimezone_idを設定していることに注意してください。ドイツのIPにアメリカのタイムゾーンは、アンチボットシステムの仕組みで説明されているように、アンチボットシステムが重視する矛盾です。SOCKS5プロキシもサポートされています("server": "socks5://host:1080")が、ChromiumはSOCKSプロキシに資格情報を送信しないため、SOCKSではIPホワイトリスト認証を使用してください。
Node.js
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ proxy: { server: 'per-context' } });
const context = await browser.newContext({
proxy: { server: 'http://gate.provider.com:7777',
username: 'customer-country-de-session-a1', password: 'pass' },
locale: 'de-DE', timezoneId: 'Europe/Berlin',
});
const page = await context.newPage();
await page.goto('https://api.ipify.org?format=json');
console.log(await page.textContent('body'));
await browser.close();
})();
Playwrightのbypassフィールド("bypass": "localhost,*.internal")は、プロキシからホストを除外します。また、launch_persistent_context()は、永続的なプロファイルディレクトリが必要な場合に同じproxyオプションを受け取ります。
Puppeteer
PuppeteerはプロキシをChromiumフラグとして渡し、ページごとに認証します:
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch({
args: ['--proxy-server=http://proxy.example.com:8080'],
});
const page = await browser.newPage();
await page.authenticate({ username: 'user', password: 'pass' }); // このページの407に応答
await page.goto('https://api.ipify.org?format=json');
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();
})();
page.authenticate()は、ナビゲーションの前に、プロキシを使用するすべてのページ(タブ)で呼び出す必要があります。プロキシはブラウザ全体に適用されます—PuppeteerにはPlaywrightのようなコンテキストごとのプロキシ設定はありません。複数のアイデンティティが必要な場合は、3つのオプションがあります:複数のブラウザプロセスを起動する(それぞれに1つのプロキシ、重いがシンプル)、--proxy-serverをローカルのスイッチングプロキシに向ける(何らかのマーカーでルーティング)、またはPlaywrightに移行する。また、--proxy-bypass-list=<-loopback>は、localhostもプロキシする必要がある場合に便利です。さらに、puppeteer-extraとそのプロキシプラグインは、認証を処理し、ページごとにローテーションできます。
Selenium
Seleniumはブラウザオプションを通じてプロキシを設定します。認証なし(IPホワイトリスト)プロキシは1行で済みますが、認証付きの場合は厄介です。
Chrome、ホワイトリスト認証
from selenium import webdriver
opts = webdriver.ChromeOptions()
opts.add_argument("--proxy-server=http://proxy.example.com:8080")
driver = webdriver.Chrome(options=opts)
driver.get("https://api.ipify.org?format=json")
print(driver.find_element("tag name", "body").text)
driver.quit()
Chrome、ユーザー名/パスワード
SeleniumのWebDriverプロトコルには、プロキシの407に応答するフックがありません。標準的な回避策は次のとおりです:
- Selenium Wire(Python):Seleniumの拡張機能で、トラフィックを独自のローカルプロキシ経由でルーティングし、認証付きアップストリームをサポートします:
Selenium Wireは現在積極的にメンテナンスされていないことに注意してください。現在のChromeでも多くの人には機能しますが、暫定的な対策として扱ってください。from seleniumwire import webdriver # pip install selenium-wire opts = {"proxy": {"http": "http://user:pass@proxy.example.com:8080", "https": "http://user:pass@proxy.example.com:8080"}} driver = webdriver.Chrome(seleniumwire_options=opts) - 生成されたChrome拡張機能:
chrome.proxyを介してプロキシを設定し、onAuthRequiredで資格情報を提供します—よく知られたパターンです。拡張機能はマニフェストと数行のバックグラウンドスクリプトで構成され、opts.add_extension(...)で読み込まれます。古いChromeのヘッドレスモードでは機能しません(拡張機能がサポートされていませんでした)。現在のheadless=newでは機能します。 - ローカルフォワーディングプロキシ:
127.0.0.1上で資格情報を保持し、アップストリームに転送します。Chromeは認証なしでそれを指すようにします。フレームワークに依存せず、堅牢です。 - プロバイダーからのホワイトリスト認証:マシンに静的IPがある場合—問題を完全に回避できます。
Firefox
opts = webdriver.FirefoxOptions()
opts.set_preference("network.proxy.type", 1)
opts.set_preference("network.proxy.http", "proxy.example.com"); opts.set_preference("network.proxy.http_port", 8080)
opts.set_preference("network.proxy.ssl", "proxy.example.com"); opts.set_preference("network.proxy.ssl_port", 8080)
opts.set_preference("network.proxy.socks_remote_dns", True) # SOCKS使用時にリモートDNSを有効化
driver = webdriver.Firefox(options=opts)
Firefoxはユーザー名/パスワードプロキシに対して認証ダイアログを表示します。ローカルフォワーダーまたはホワイトリストのアプローチが適用されます。
ヘッドレスブラウザでプロキシが解決しない問題
本物のブラウザはTLSおよびHTTP/2フィンガープリントを通過させます—ハンドシェイクは実際にChromeのものです(TLSフィンガープリントを参照)。しかし、それだけではJavaScriptレイヤーを通過できません:
navigator.webdriverは自動化時にtrueになります。サイトは最初にこれをチェックします。- ヘッドレスモードにはレンダリングとAPIの違い(プラグインの欠落、特定のWebGLレンダラー文字列、ウィンドウ寸法)があり、フィンガープリントスクリプトがテストします。Chromeの新しいヘッドレス(
headless=new)はヘッド付きにかなり近いですが、同一ではありません。 - WebRTCは、無効化または偽装しない限り、マシンの実際のIPを公開する可能性があります。プロキシはそれに触れません。テストしてください—プロキシのテスト方法。
- タイムゾーン、ロケール、地理位置情報は、設定しない限りマシンから取得されます(Playwright:
timezone_id、locale、geolocation)。プロキシの国との不一致は典型的な兆候です。 - 動作:即時ナビゲーション、マウスの動きなし、毎回同じタイミング。
ステルスプラグイン(puppeteer-extra-plugin-stealth、playwright-stealth)は最も明白な痕跡を修正します。アンチディテクトブラウザはさらに進んで、プロファイルごとに一貫したフィンガープリントを提供し、Playwright/Puppeteerスクリプトが接続するデバッグポートを公開します—これはアカウント作業の本番環境での答えです。アンチディテクトブラウザとはを参照し、各プロファイルの背後にあるIPタイプの選択については、アンチディテクトプロキシランキングを参照してください。
プロキシ作業のためのフレームワークの選択
| Playwright | Puppeteer | Selenium | |
|---|---|---|---|
| 認証付きプロキシ | ネイティブ(username/passwordフィールド) | ページごとにpage.authenticate() | 回避策が必要(Wire、拡張機能、ローカルフォワーダー) |
| セッションごとに異なるプロキシ | コンテキストごと、1つのブラウザ | プロキシごとに1つのブラウザ | プロキシごとに1つのドライバー |
| SOCKS5 | はい(資格情報なし→ホワイトリスト) | フラグ経由(資格情報なし) | オプション/設定経由 |
| セッションごとのロケール/タイムゾーン | ネイティブのコンテキストオプション | エミュレーションAPI/フラグ | 設定/CDP |
| 最適な用途 | マルチアイデンティティのスクレイピングとテスト | Node中心のChrome自動化 | レガシースイート、クロスブラウザグリッド |
よくある質問
Playwrightで認証付きプロキシを使用するには?
launch()にproxy={"server": "http://host:port", "username": "…", "password": "…"}を渡すか、コンテキストごとにnew_context()に渡します(最初にproxy={"server": "per-context"}で起動)。
Puppeteerで認証付きプロキシを使用するには?
args: ['--proxy-server=host:port']で起動し、各ページでpage.goto()の前にawait page.authenticate({username, password})を呼び出します。
なぜChromeは--proxy-serverでuser:pass@を無視するのですか?
Chromiumのフラグはscheme://host:portのみを受け付け、資格情報は解析されません。プロキシの407には対話型ダイアログで応答するため、自動化はフレームワークのメカニズムを通じて資格情報を提供する必要があります。
タブごとに異なるプロキシを使用できますか?
タブごとにはできません。Playwrightはブラウザのコンテキストごとに行います(各コンテキストは分離されたセッションです)。PuppeteerとSeleniumは、プロキシごとに1つのブラウザインスタンス、またはローカルのスイッチングプロキシが必要です。
プロキシを使用するとヘッドレスChromeは検出されなくなりますか?
いいえ。IPレイヤーと、実際のブラウザであるためTLSレイヤーを修正します。自動化フラグ、ヘッドレスの痕跡、WebRTC、タイムゾーンの不一致、動作は別のシグナルであり、個別の処理が必要です。
ブラウザ自動化にはレジデンシャルプロキシとデータセンタープロキシのどちらを使用すべきですか?
ターゲットのIPポリシーに応じて—ブラウザはその計算を変更しません。許容される場合はデータセンター、保護されたサイトではレジデンシャルまたはモバイル、永続的なログインプロファイルには静的(ISP)を使用します。プロキシタイプの比較を参照してください。