這是每個瀏覽器自動化開發者都會恰好踩一次的坑:你往 Chrome 的啟動引數里加了 --proxy-server=http://user:pass@host:port,瀏覽器正常啟動了,然後每個頁面都卡在一個你指令碼看不見也點不到的認證彈窗上。Chrome 默默地把代理引數裡的憑證給剝掉了。沒有報錯,沒有日誌,就只有一個彈在沒人盯著的瀏覽器裡的模態對話方塊。
這份指南是 2026 年在 Selenium 和 Playwright 裡真正能用的代理認證方法的完整地圖——該用哪個、該躲哪個,以及每個的確切程式碼。(關於這些工具裡的代理選擇與輪換策略,見 在 Playwright 和 Puppeteer 裡使用代理——本文只講怎麼把憑證送進去。)
命令列 HTTP 客戶端會從代理 URL 裡解析出憑證,並自動用一個 Proxy-Authorization 頭來應答代理的 407 Proxy Authentication Required。Chromium 不會:--proxy-server 只接受 scheme://host:port,當 407 回來時它會彈出一個互動式對話方塊。在 headless 模式下連對話方塊都沒有——請求直接失敗。
所以問題從來不是"我怎麼把密碼放進 URL"——而是"哪一層替我應答這個 407"。四個能用的答案,最好的在前。
Playwright 把這個問題正經地解決了:它透過 CDP 自己應答代理認證質詢。憑證放進啟動選項或 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 - 以及按 context 設定,這才是它強大的地方:
const browser = await chromium.launch({
proxy: { server: 'per-context' } // 在啟動時宣告意圖
});
const ctx = await browser.newContext({
proxy: {
server: 'http://us.jibaoproxy.com:913',
username: 'USERNAME-session-job2',
password: 'PASSWORD',
}
});
按 context 設定代理,意味著一個瀏覽器程序可以在 N 個不同的 sticky 會話上跑 N 個 context——這是每套正經 Playwright 爬取方案的基石。如果你用的是 Playwright,那你搞定了;直接跳到驗證一節。下面這一切之所以存在,是因為 Selenium 沒有等價物。
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")
上生產之前你該知道的幾個注意點:
經典做法:一個動態生成的小擴充套件,它設定代理並透過 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)
兩個坑:擴充套件在經典 headless 模式下不載入——用 --headless=new(Chrome 109+)或者以有頭方式執行;還有,Manifest V2 的 background 指令碼對旁載入的自動化擴充套件仍然可用,但要留意 Chrome 的 MV2 棄用時間表——MV3 的等價做法需要一個 service worker 和同樣的 onAuthRequired 監聽器。
跑一個持有憑證的小型本地代理;讓瀏覽器指向 localhost、完全不帶認證。它對每種瀏覽器、每個驅動、每種語言都管用,無論 headless 與否:
# 用 pproxy (pip install pproxy) - 終端 1:
pproxy -l http://127.0.0.1:8899 \
-r "http://USERNAME:[email protected]:913"
# 你的指令碼 - 終端 2:純 Selenium,不需要認證
opts = webdriver.ChromeOptions()
opts.add_argument("--proxy-server=http://127.0.0.1:8899")
driver = webdriver.Chrome(options=opts)
這也是 Firefox/geckodriver(擴充套件那一招在這裡不適用)以及像 Electron 應用測試這類特殊環境裡最乾淨的答案。代價:多了一個需要照看的活動部件,而且按 context 路由時每個會話需要一個轉發器埠。
| 方法 | 適用於 | Headless | 按 context 會話 | 生產裁決 |
|---|---|---|---|---|
| Playwright 原生 | Playwright | 是 | 是 | 預設首選 |
| selenium-wire | Selenium (Py) | 是 | 按驅動 | 中等規模夠用 |
| 認證擴充套件 | Selenium(任意語言) | 僅 --headless=new | 按驅動 | 穩妥,留意 MV3 |
| 本地轉發器 | 一切 | 是 | 每會話一個埠 | 萬能兜底 |
靜默回退到你的真實 IP,是會讓賬號被封的那種失敗模式。在每次執行開始時斷言出口 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-server 裡傳了憑證;Chrome 把它們丟了。改用四種方法之一。ERR_PROXY_CONNECTION_FAILED——host/port 寫錯了或協議不匹配。先用 curl -x 測同一行;如果 curl 能通,那問題出在你的瀏覽器接線上。--headless=new。瀏覽器不讀 user:pass@ 形式的代理 URL——必須得有東西替它們應答 407。在 Playwright 裡這個東西是內建的;在 Selenium 裡它是 selenium-wire、一個生成的認證擴充套件,或者一個本地轉發器。按你的技術棧從對比表裡挑一個,然後在每次執行時都斷言出口 IP,這樣一次靜默的認證失敗就永遠不可能在爬取中途洩露你的真實地址。
新用戶註冊即送 500M免費流量,首次儲值另有贈金。優惠限時供應。