Selenium 與 Playwright 的 Proxy 驗證:所有可行的方法(2026)

發佈於 2026年6月4日 · 約 10 分鐘閱讀

這是每個瀏覽器自動化開發者都會恰好踩一次的坑:你往 Chrome 的啟動引數里加了 --proxy-server=http://user:pass@host:port,瀏覽器正常啟動了,然後每個頁面都卡在一個你指令碼看不見也點不到的認證彈窗上。Chrome 默默地把代理引數裡的憑證給剝掉了。沒有報錯,沒有日誌,就只有一個彈在沒人盯著的瀏覽器裡的模態對話方塊。

這份指南是 2026 年在 Selenium 和 Playwright 裡真正能用的代理認證方法的完整地圖——該用哪個、該躲哪個,以及每個的確切程式碼。(關於這些工具裡的代理選擇與輪換策略,見 在 Playwright 和 Puppeteer 裡使用代理——本文只講怎麼把憑證送進去。)

為什麼 user:pass@host 在瀏覽器裡失效

命令列 HTTP 客戶端會從代理 URL 裡解析出憑證,並自動用一個 Proxy-Authorization 頭來應答代理的 407 Proxy Authentication Required。Chromium 不會:--proxy-server 只接受 scheme://host:port,當 407 回來時它會彈出一個互動式對話方塊。在 headless 模式下連對話方塊都沒有——請求直接失敗。

所以問題從來不是"我怎麼把密碼放進 URL"——而是"哪一層替我應答這個 407"。四個能用的答案,最好的在前。

方法一:Playwright 原生認證(能用就用這個)

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(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")

上生產之前你該知道的幾個注意點:

方法三:用 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)

兩個坑:擴充套件在經典 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-wireSelenium (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, "代理未生效 - 在洩露之前中止"
免費工具 · 無需註冊

用肉眼核查你的自動化瀏覽器

把你的 Selenium/Playwright 瀏覽器開到我們的 What Is My IP 頁面:它在一個檢視裡顯示出口 IP、地理位置、ASN 型別和代理/VPN 標記——即時確認認證層生效了、IP 是住宅的。

開啟 IP 檢測器 →

在一個"住宅"代理上看到資料中心 ASN?換一個真正住宅的池子——500M免費流量 →

故障排查速查

小結

瀏覽器不讀 user:pass@ 形式的代理 URL——必須得有東西替它們應答 407。在 Playwright 裡這個東西是內建的;在 Selenium 裡它是 selenium-wire、一個生成的認證擴充套件,或者一個本地轉發器。按你的技術棧從對比表裡挑一個,然後在每次執行時都斷言出口 IP,這樣一次靜默的認證失敗就永遠不可能在爬取中途洩露你的真實地址。

今晚把四種方法都試一遍

500M免費流量——一個閘道器,sticky 或輪換,HTTP 和 SOCKS5 都有。

免費試用

適用於所有 IP 產品 · 龐大的節點池隨時可用

立即註冊,儲值最高可享 100% 返現

新用戶註冊即送 500M免費流量,首次儲值另有贈金。優惠限時供應。