# Puppeteer代理设置：标志、认证、轮换与现实

启动标志很简单；随后的407是大多数Puppeteer代理设置失败的地方。这里是完整的模式——page.authenticate、上下文轮换、proxy-chain——以及关于每页代理和无头检测的真相。

Puppeteer代理设置从一个启动标志开始，对于大多数人来说，下一步就遇到了障碍：代理返回`407 Proxy Authentication Required`，因为`--proxy-server`无法携带凭据。解决方法是内置的——`page.authenticate()`——但周围充满了半有效的建议：npm包悄悄地通过Node.js重路由你的流量，Chromium无法认证的SOCKS方案，以及使工作代理看起来失效的localhost绕过。本指南介绍了在生产环境中可靠的设置：标志、认证、浏览器上下文轮换、proxy-chain用于棘手的情况，以及关于无头检测的诚实部分。

## Puppeteer代理设置：基础模式

代理是一个Chromium启动参数，因此适用于整个浏览器。凭据通过`page.authenticate()`传递，它通过DevTools协议响应代理的407挑战——在任何导航之前调用：

```js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({
    args: ['--proxy-server=http://residentialpremium.quantumproxies.io:8080'],
  });
  const page = await browser.newPage();
  await page.authenticate({ username: 'USER', password: 'PASS' });

  await page.goto('https://httpbin.org/ip', { waitUntil: 'domcontentloaded' });
  console.log(await page.evaluate(() => document.body.innerText)); // exit IP
  await browser.close();
})();
```

四个细节可以节省调试时间：

- **使用模板字面量或连接符构建标志，而不是简单的引号。** 一个经典的Stack Overflow错误：双引号中的`"--proxy-server =..."`带有插值占位符从未替换变量——而且多余的空格也会破坏解析。
- **包括方案。** `--proxy-server=socks5://host:port`用于SOCKS，否则Chromium假定为HTTP。
- **不要在标志中嵌入`user:pass@`。** Chromium会忽略它；只有`page.authenticate()`（或IP白名单）可以认证。
- **localhost绕过代理。** Chromium跳过环回URL的代理——在Puppeteer问题#3711中记录的一个难题。如果你确实需要代理本地流量，请添加`--proxy-bypass-list=<-loopback>`；否则只需测试外部URL。

![Puppeteer 代理认证的四步流程：--proxy-server 参数设置地址，page.authenticate() 通过 DevTools 协议注册凭据，网关发出 407 挑战，Chromium 在不弹出对话框的情况下作出响应，于是页面从住宅出口 IP 加载。](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335144/blog/generated/qp-b9-005-diag1.png)
*page.authenticate通过DevTools协议注册凭据；当网关发送407时，Chromium在不显示对话框的情况下响应。*

## 通过浏览器上下文轮换代理

每个IP重新启动Chrome需要几秒钟和数百MB的内存。浏览器上下文解决了这个问题：自Puppeteer v22起，API是`browser.createBrowserContext()`（取代了旧的隐身变体），它接受`proxyServer`选项，并在毫秒内创建一个具有自己cookie和存储的上下文：

```js
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const jobs = ['https://example.com/a', 'https://example.com/b'];

  for (const url of jobs) {
    const context = await browser.createBrowserContext({
      proxyServer: 'http://residentialpremium.quantumproxies.io:8080',
    });
    const page = await context.newPage();
    await page.authenticate({ username: 'USER', password: 'PASS' });
    try {
      await page.goto(url, { timeout: 30000 });
      // ...extract...
    } finally {
      await context.close();
    }
  }
  await browser.close();
})();
```

对于旋转网关，每个上下文自然从池中的不同地址退出——使用[旋转住宅代理](https://quantumproxies.io/rotating-proxies)，这意味着在一个主机名后面有90M+ IP跨越200+国家，并且当多页流程需要连续性时，粘性会话用户名参数可以固定一个出口。这是我们为[Playwright](https://quantumproxies.io/blog/playwright-proxy-integration)推荐的相同的每个作业上下文架构；Puppeteer只是明确地拼写了认证步骤。

两个习惯保持轮换的诚实。在开发过程中记录每个上下文的出口IP——在上下文开始时命中一个IP回显端点，并将其与抓取的行一起存储，这样当目标开始软封锁时，你可以判断是一个出口还是一个指纹是罪魁祸首。并且限制你的并发：每个上下文都很便宜，但每个打开的页面仍然占用渲染器内存，因此在上下文创建周围使用信号量比在作业列表增长到数千个URL时使用无限循环更好。

## proxy-chain：用于棘手认证的本地桥

两个情况打破了标志加认证模式：认证的SOCKS5（Chromium根本没有SOCKS凭据支持）和仅接受不带认证步骤的裸代理URL的工具。`proxy-chain` npm包通过启动一个本地的、无凭据的代理来解决这两种情况，该代理转发到你的认证上游：

```js
const puppeteer = require('puppeteer');
const proxyChain = require('proxy-chain');

(async () => {
  const upstream = 'http://USER:PASS@residentialpremium.quantumproxies.io:8080';
  const localUrl = await proxyChain.anonymizeProxy(upstream);
  // localUrl is something like http://127.0.0.1:54321 — no credentials needed

  const browser = await puppeteer.launch({
    args: ['--proxy-server=' + localUrl],
  });
  const page = await browser.newPage();
  await page.goto('https://httpbin.org/ip');

  await browser.close();
  await proxyChain.closeAnonymizedProxy(localUrl, true);
})();
```

关键是，页面的请求仍然从Chrome本身发出——proxy-chain只转发字节，因此你的TLS指纹保持为真实浏览器的。这一区别是下一节的重点。

## 每页代理：诚实的答案

Puppeteer没有原生的每页代理，而流行的解决方案——`puppeteer-page-proxy`、`puppeteer-proxy`——拦截每个请求并从Node.js重新发出，然后将响应反馈给浏览器。三个后果：目标现在看到的是Node TLS握手而不是Chrome的，这在受保护的网站上会被[JA3/JA4指纹识别](https://quantumproxies.io/blog/tls-ja3-fingerprinting-scraping)立即标记；每个请求都需要通过Node的往返；这两个包实际上都没有维护，安装时就已经在其自身的问题跟踪器中被破坏。如果你需要为不同页面使用不同的IP，请像上面那样为每个代理使用一个上下文——效果相同，真实的Chrome流量，受支持的API。

![在 Puppeteer 中轮换代理的三种方式访问同一目标：每个 IP 重新启动一次 Chrome 需要数秒和数百 MB 内存；每个代理一个浏览器上下文，几毫秒即可创建，流量仍是真正的 Chrome 流量；Node 重路由包则会换上 Node 的 TLS 握手，立刻被指纹检测标记。](https://res.cloudinary.com/dmqliab0t/image/upload/f_auto,q_auto,w_1200/v1785335144/blog/generated/qp-b9-005-diag2.png)
*上下文为你提供了真正的Chrome流量轮换。Node重路由包将你的TLS指纹换成机器人的——这与代理的目的相反。*

## 无头检测的现实

代理修复了网络层；它无法使无头Chrome隐形。旧的无头模式通过HeadlessChrome User-Agent标记自己；新的无头模式（Puppeteer自v22以来的默认设置）共享真实浏览器的架构，缩小了这一差距，但检测器仍然会探测`navigator.webdriver`、CDP副作用和渲染怪癖——而隐身插件修补的是昨天的检查，而不是明天的。按努力回报顺序安排你的修复：首先是干净的[住宅IP](https://quantumproxies.io/residential-proxies)，因为声誉是网站运行的最便宜的过滤器，也是你的代码无法伪造的；其次是合理的头信息和节奏（我们的[避免CAPTCHA](https://quantumproxies.io/blog/avoid-captcha-while-scraping)指南涵盖了触发信号）；当一个强化的目标仍然胜出时，通过一个[Scraper API](https://quantumproxies.io/scraper-api)路由该域名，该API处理渲染、指纹和重试，并返回干净的HTML、markdown或JSON——一个HTTP调用而不是一群修补过的浏览器。

## 常见问题

### 如何在Puppeteer中认证代理？

在启动时使用`args: ['--proxy-server=http://host:port']`设置地址，然后在每个页面导航之前调用`await page.authenticate({ username, password })`。嵌入在标志URL中的凭据会被Chromium忽略。对于带认证的SOCKS5，使用proxy-chain作为桥梁，因为Chromium无法发送SOCKS凭据。

### Puppeteer可以为每个页面使用不同的代理吗？

不是原生支持——启动标志是浏览器范围的。支持的等效方法是通过`browser.createBrowserContext({ proxyServer })`为每个代理创建一个浏览器上下文，并在每个上下文中放置页面。承诺真正每页代理的包会通过Node.js重路由请求，改变你的TLS指纹，并被严肃的反机器人系统标记。

### Puppeteer支持SOCKS5代理吗？

是的，对于未经认证的端点：传递`--proxy-server=socks5://host:port`。认证的SOCKS5会失败，因为Chromium没有SOCKS凭据机制，而`page.authenticate()`只响应HTTP 407挑战。解决方法：使用网关的HTTP端口进行认证，将你的IP列入白名单，或运行proxy-chain作为本地桥。

### 如何在Puppeteer中轮换代理？

为每个作业创建一个新的浏览器上下文，使用`createBrowserContext({ proxyServer })`并指向一个旋转网关——每个上下文然后自动从一个新的IP退出，无需管理代理列表。每个IP重新启动整个浏览器也可以，但每次轮换需要几秒钟和数百MB的RAM。

### 为什么我的Puppeteer代理不适用于localhost？

Chromium设计上绕过环回地址的代理，因此对localhost或127.0.0.1的请求直接进行——这种行为让足够多的人感到惊讶，以至于成为一个编号的Puppeteer问题。添加`--proxy-bypass-list=<-loopback>`以强制代理，或简单地验证你的代理对外部IP回显端点。

持久的模式很小：地址的标志，`page.authenticate()`用于凭据，上下文用于轮换，proxy-chain用于棘手的情况——以及对任何将你的请求移出浏览器的包的怀疑。给这个堆栈干净的住宅出口，Puppeteer就会保持无趣，这是基础设施能获得的最高赞美。

[在住宅代理上运行Puppeteer](https://quantumproxies.io/residential-proxies)
