快速回答
如何在 Puppeteer 中使用认证代理?
启动 Chrome 时使用 --proxy-server=http://gw.crawlrelay.com:7777,然后在首次 goto 前调用 page.authenticate({ username, password })。Chrome 会忽略写入启动参数中的认证信息。CrawlRelay 住宅代理通过用户名读取国家和固定会话ID,每个页面或上下文可以有自己的出口。流量费用从 50 GB 起计 US$0.50/GB。支持加密货币支付,无需 KYC。
Puppeteer 快速搭建指南
| 代理地址 | --proxy-server=http://gw.crawlrelay.com:7777 位于 args,或浏览器上下文使用 proxyServer |
|---|---|
| 认证凭据 | 在导航前调用 await page.authenticate({ username, password }) |
| 会话隔离 | browser.createBrowserContext({ proxyServer }):每个会话一个上下文 |
| SOCKS5 | Chrome 认证不支持:请使用 HTTP 端口 |
| 节省流量 | page.setRequestInterception(true) 并且阻止图片、字体和媒体请求 |
如何设置单个认证代理?
这是最简示范。try … finally 代码块即使导航失败也会关闭 Chrome,在服务器上防止孤儿浏览器堆积非常重要。
import puppeteer from "puppeteer";
const browser = await puppeteer.launch({
args: ["--proxy-server=http://gw.crawlrelay.com:7777"],
});
try {
const page = await browser.newPage();
await page.authenticate({ username: "USERNAME-country-us", password: "PASSWORD" });
await page.setRequestInterception(true);
page.on("request", (req) =>
["image", "font", "media"].includes(req.resourceType()) ? req.abort() : req.continue()
);
const res = await page.goto("https://example.com/", { waitUntil: "domcontentloaded", timeout: 60000 });
console.log(res.status(), await page.title());
} finally {
await browser.close();
}如何在一个浏览器中运行多个会话或多个国家代理?
为每个会话创建一个浏览器上下文。上下文是独立的配置文件,拥有自己的 Cookie、缓存和网络状态,因此给一个上下文的凭据不会泄露到另一个。为每个上下文分配带有特定国家或会话 ID 的用户名。
import puppeteer from "puppeteer";
import { randomUUID } from "node:crypto";
const GATEWAY = "http://gw.crawlrelay.com:7777";
const browser = await puppeteer.launch();
async function visit(country, url) {
const session = randomUUID().replaceAll("-", "").slice(0, 10);
const context = await browser.createBrowserContext({ proxyServer: GATEWAY });
try {
const page = await context.newPage();
await page.authenticate({
username: `USERNAME-country-${country}-session-${session}-ttl-20`,
password: "PASSWORD",
});
await page.goto(url, { waitUntil: "domcontentloaded", timeout: 60000 });
return { country, session, ip: await page.evaluate(() => document.body.innerText.trim()) };
} finally {
await context.close();
}
}
try {
const results = await Promise.all([
visit("us", "https://api.ipify.org"),
visit("gb", "https://api.ipify.org"),
]);
console.table(results);
} finally {
await browser.close();
}Puppeteer 为什么显示 407 或 ERR_TUNNEL_CONNECTION_FAILED?
因为 Chrome 没有发送凭据或发送了错误的凭据。请确认三点:
page.authenticate()必须在该页面第一次goto前调用。--proxy-server参数或proxyServer仅包含协议、主机和端口,不带user:pass@部分。- 用户名的目标部分无拼写错误:先用 curl 测试,参考 407 页面。
如果使用相同用户名和密码 curl 成功而 Puppeteer 仍失败,请参阅 ERR_TUNNEL_CONNECTION_FAILED。
Puppeteer 页面流量费用是多少?
Chrome 下载的所有资源均计费:HTML、脚本、样式表、图片、字体以及页面发出的 API 请求。HTTP Archive Web Almanac 2025 测得移动端中位页面大小为 2,164 KB,桌面端为 2,412 KB。通过请求拦截屏蔽图片、字体和媒体通常能将流量减少到几百 KB,再用缓存响应重复脚本能进一步降低。仅对需要页面使用旋转](/mobile-proxies/) 移动代理:移动流量从 5 GB 起计 US$1.50/GB,住宅代理流量从 50 GB 起计 US$0.50/GB。
Puppeteer 与代理:常见问题
我可以把用户名和密码写进 --proxy-server 吗?
不行。Chrome 会忽略 --proxy-server 标志里的认证信息,第一个 HTTPS 请求就会以 407 错误失败,这个错误隐藏在 ERR_TUNNEL_CONNECTION_FAILED 中。启动参数只写 http://host:port,凭据必须在每个新页面通过 page.authenticate() 传递。
如何在 Puppeteer 中实现页面间 IP 轮换?
为每个页面开一个新的浏览器上下文,或者给每个页面分配一个没有会话 ID 的用户名。新上下文会建立新的连接,每个连接通常分配一个不同住宅出口。同一页面内,Chrome 会复用连接,因此发往同一站点的请求常常共享同一个出口,直到连接关闭。
page.authenticate() 会与请求拦截同时工作吗?
会。Puppeteer 会自行处理代理的认证挑战,拦截处理器只需要对每个请求调用 continue() 或 abort() 即可。先设置 authenticate(),然后开启拦截,如首个示例所示。
用代理时应使用 puppeteer-extra 隐身插件吗?
我们不支持也不推荐使用旨在隐藏自动化或绕过机器人检测的工具。这类工具的目的是规避网站对自动访问者的限制,违反了我们的可接受使用政策。建议以合理速度渲染公共页面,使用网站提供的官方 API。
Puppeteer 代理中使用的是哪个版本的 Chrome?
新版本 Puppeteer 默认下载匹配的 Chrome for Testing 版本并使用。代理参数和 page.authenticate() 在它里面的表现与常规 Chrome 一致。如果你让 Puppeteer 使用自己的 Chrome(通过 executablePath 指定),请保证浏览器保持最新。
通过住宅代理运行 Puppeteer
US$5.94 适用于 10 GB,US$0.50/GB 来自 50 GB。