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 里解析出凭证,并自动用一个 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产品通用 · 海量节点随时可用

现在加入,立享最高20%充值返现

新用户注册即送500M免费流量,首次充值额外加赠,活动期间限时开放。