# Zendriver代理与身份验证：设置与解决方案

Zendriver是nodriver的社区维护分支——修复速度更快，但仍存在相同的身份验证代理问题。以下是完整的代理设置、实际差异以及使用户：密码生效的解决方案。

**zendriver代理**的设置与nodriver完全相同——这既是好消息也是问题所在。zendriver（`cdpdriver/zendriver`项目）是nodriver的社区维护分支：一个异步优先、未检测的浏览器自动化框架，直接通过DevTools协议驱动Chrome，没有WebDriver。它的存在是因为nodriver的单一维护者很少合并外部修复，因此社区进行了分支以接受错误修复、添加功能并在GitHub上处理问题。它没有修复的是身份验证代理。本指南涵盖完整的代理设置、与nodriver的实际差异以及使`user:pass`生效的解决方案。

## 安装和基本代理设置

安装只需一行——`pip install zendriver`——API几乎与nodriver逐符号镜像，因此在移植脚本时`import zendriver as zd`通常是唯一的变化。未认证的代理通过`browser_args`，请求从代理IP退出：

```python
import zendriver as zd

async def main():
    browser = await zd.start(
        browser_args=["--proxy-server=residentialboson.quantumproxies.io:PORT"],
    )
    page = await browser.get("https://httpbin.org/ip")
    print(await page.get_content())   # shows the proxy exit IP
    await browser.stop()

zd.loop().run_until_complete(main())
```

这之所以有效是因为它只是一个Chrome标志。添加凭据——`--proxy-server=http://USER:PASS@host:port`——Chromium会静默丢弃`USER:PASS@`部分，代理回复`407`，并出现一个zendriver无法填充的本地登录对话框。这是Chrome的限制，而不是zendriver的错误，因此没有版本更新会使该标志接受密码。

## zendriver代理身份验证问题

该问题在zendriver的问题中公开跟踪——一个功能请求线程（#10）和一个专门的“带身份验证的代理”问题（#208）——这本身就是一个值得注意的差异：在nodriver上，同样的问题被埋在一个讨论中，维护者回答一次就不再理会。问题#10上的一位用户直言不讳地总结了现状：代理服务器选项没有身份验证方式，因此他们使用代理扩展，效果很好。这是经过实地验证的共识，直接指向nodriver用户依赖的相同三个修复。

## 修复1：IP白名单（最简单）

如果您的工作在具有稳定公共IP的机器上运行，则完全跳过凭据。在您的提供商仪表板中注册出口IP，网关通过源地址对您进行身份验证——zendriver代码保持上述简单的`--proxy-server`片段，没有身份验证逻辑。每个QuantumProxies计划都支持IP白名单和用户：密码，这使得当您的IP固定时，这是默认建议。唯一的限制是它对机器而不是脚本进行身份验证，因此NAT后的临时运行器和容器需要以下两种方法之一。

![nodriver 与 zendriver 的并排对比：CDP 架构、隐身能力和 API 相同，但前者只有一位很少合并外部修复的维护者，后者是社区分支，有开放的问题跟踪器，发布也更稳定。卡片展示了沿用下来的部分，包括在 issue #10 和 #208 中跟踪的代理认证缺陷。](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785776550/blog/generated/qp-b10-002-diag1.png)
*zendriver保留了nodriver的隐身和API，同时添加了一个开放的问题跟踪器——然而，代理身份验证问题仍然未变。*

## 修复2：通过CDP回答挑战

因为zendriver以与nodriver相同的方式暴露了DevTools协议，您可以在进程中拦截身份验证挑战：注册`RequestPaused`和`AuthRequired`处理程序，然后启用`Fetch`域，设置`handle_auth_requests=True`并回复`continue_with_auth`。两个不明显的规则与nodriver相同——在启用域*之前*添加处理程序，并使用`asyncio.create_task`触发响应，以便等待它们不会导致循环死锁：

```python
import asyncio
import zendriver as zd

async def main():
    browser = await zd.start(browser_args=["--proxy-server=residentialpremium.quantumproxies.io:8080"])
    tab = await browser.get("data:,")            # blank tab first

    async def on_auth(event):
        asyncio.create_task(tab.send(zd.cdp.fetch.continue_with_auth(
            request_id=event.request_id,
            auth_challenge_response=zd.cdp.fetch.AuthChallengeResponse(
                response="ProvideCredentials", username="USER", password="PASS",
            ),
        )))

    async def on_request(event):
        asyncio.create_task(tab.send(
            zd.cdp.fetch.continue_request(request_id=event.request_id)))

    # handlers FIRST, then enable the domain
    tab.add_handler(zd.cdp.fetch.RequestPaused, on_request)
    tab.add_handler(zd.cdp.fetch.AuthRequired, on_auth)
    await tab.send(zd.cdp.fetch.enable(handle_auth_requests=True))

    page = await browser.get("https://httpbin.org/ip")
    await asyncio.sleep(3)
    print(await page.get_content())
    await browser.stop()

zd.loop().run_until_complete(main())
```

处理程序顺序为何重要以及出错时会发生什么的完整演练，请参阅我们的[nodriver代理身份验证指南](https://quantumproxies.io/blog/nodriver-proxy-authentication)——机制是共享的，因此没有理由重复两次。

## 修复3：代理身份验证扩展和SOCKS5

问题#10推荐的路线是生成的Chrome扩展：Manifest V3清单加上设置代理并回答`chrome.webRequest.onAuthRequired`的工作程序，使用`--load-extension`在`--headless=new`下加载。它可以处理任何类型的代理，包括SOCKS5，这很重要，因为经过身份验证的SOCKS5从未通过标志工作——Chromium没有为SOCKS5实现用户名/密码支持（Chromium bug 40829748）。SOCKS5的替代方案是一个本地中继，持有凭据并在`127.0.0.1`上提供无身份验证端点，详见[代理中继指南](https://quantumproxies.io/blog/proxy-relay-socks5-auth-tools)。每个QuantumProxies计划都提供HTTP和[SOCKS5端点](https://quantumproxies.io/socks5-proxies)，因此您通常可以通过使用HTTP来绕过整个问题，HTTP可以干净地处理基本身份验证。

## 与nodriver的实际差异

分支不是表面上的。在将nodriver、zendriver、Selenium和Playwright与现代反机器人系统对比的公开基准测试中，nodriver/zendriver家族在通过方面最强，zendriver由于携带未合并的上游修复而稍微领先。实际上，影响代理工作的差异是：一个活跃的问题跟踪器，问题得到分类，更稳定的发布节奏，可以每个会话启动的隔离浏览器上下文，以及从nodriver保留的内置便利功能。这些都没有解决身份验证问题——但这意味着修复到达时会更快，并且使zendriver成为运行多个并行会话的更简单的分支。对于在这些并发上下文中旋转和池化出口，我们关于[代理池管理](https://quantumproxies.io/blog/proxy-pool-management-best-practices)的笔记适用于zendriver，无论您是通过[旋转代理](https://quantumproxies.io/rotating-proxies)路由还是为登录流固定粘性会话。

一个澄清：在docs.rs上也存在一个名为`zendriver`的独立Rust crate。它与这里讨论的Python分支无关——如果您在Python中进行抓取，`pip install zendriver`是您需要的。

![实现 zendriver 认证代理的路径：安装 zendriver，用只包含主机和端口的 --proxy-server 参数启动，然后把稳定的出口 IP 加入白名单，或在 IP 变化时用 CDP Fetch 处理程序响应认证挑战。卡片注明，在该参数中写 user:pass 是死路一条。](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785776550/blog/generated/qp-b10-002-diag2.png)
*当您的出口IP稳定时使用白名单；当不稳定时回答CDP挑战。无论哪种方式，用户：密码标志都是死胡同。*

## 常见问题解答

### 如何在zendriver中使用代理？

在调用`zendriver.start()`时通过`browser_args`传递地址：`browser_args=["--proxy-server=host:port"]`。这会将所有流量路由到未认证的端点的代理。对于认证代理，您不能在标志中放置`user:pass`——将您的IP列入白名单，使用CDP `Fetch.AuthRequired`处理程序，或加载代理身份验证扩展。

### zendriver支持认证代理吗？

没有内置参数——问题#10和#208中跟踪了这个缺口。Chromium忽略代理标志中的凭据，因此您需要通过其他方式进行身份验证：在提供商处进行IP白名单，在进程中回答挑战的CDP处理程序，生成的Chrome扩展，或持有凭据的本地中继。

### nodriver和zendriver有什么区别？

zendriver是nodriver的社区维护分支，具有相同的CDP架构、隐身目标和API。区别在于维护：zendriver在GitHub上接受问题和拉取请求，发布未合并的上游错误修复，并更定期发布。代理身份验证在两者中表现相同——本指南中的修复适用于两者。

### zendriver可以使用经过身份验证的SOCKS5代理吗？

不能通过标志，因为Chromium从未实现SOCKS5用户名/密码身份验证（Chromium bug 40829748），zendriver继承了这一点。使用代理身份验证扩展，运行添加凭据的本地中继，或将zendriver指向您的提供商的HTTP端点——HTTP基本代理身份验证在SOCKS5身份验证不起作用的地方可靠。

zendriver是今天构建的两个分支中更锋利的一个，但它给您带来了与nodriver相同的身份验证代理问题。当您的IP固定时使用白名单，当不固定时回答CDP挑战，并将扩展和中继作为备选方案。无论选择哪种方式，出口IP都起到了关键作用——在烧毁的数据中心地址上的维护分支仍然会被阻止。

[为zendriver提供干净的住宅出口](https://quantumproxies.io/residential-proxies)
