Playwright 和 Puppeteer 配代理
发布:2026 年 7 月 23 日 · 阅读约 6 分钟
一句话总结: Playwright 里把 proxy dict 传给 launch(),更好的是传给 new_context(),让每个 context 拿各自的 IP。Puppeteer 里把 --proxy-server 放进 args,凭据用 page.authenticate()。用住宅代理让浏览器从真实家庭 IP 出去;同时跑多个身份时,每个 context/浏览器用各自的粘性会话。
Playwright
Playwright 接收一个 proxy 字典,含纯 server URL 和独立的凭据字段。最简单的形式设在 launch() 上,作用于整个浏览器:
from playwright.sync_api import sync_playwright
with sync_playwright() as p:
browser = p.chromium.launch(
proxy={
"server": "http://gw.roamproxy.com:41080",
"username": "YOUR_USERNAME",
"password": "YOUR_PASSWORD",
}
)
page = browser.new_page()
page.goto("https://ip.sb")
print(page.inner_text("body"))
browser.close()
per-context 代理——一身份一 IP
更有用的写法是把代理设在 new_context() 上。每个 context 是隔离的浏览器会话——各自的 cookie、存储,现在还有各自的 IP——所以一个浏览器进程能跑多个不共用出口的身份:
ctx_a = browser.new_context(proxy={
"server": "http://gw.roamproxy.com:41080",
"username": "USERNAME_session_a",
"password": "YOUR_PASSWORD",
})
ctx_b = browser.new_context(proxy={
"server": "http://gw.roamproxy.com:41080",
"username": "USERNAME_session_b",
"password": "YOUR_PASSWORD",
})
给每个 context 在用户名里用不同的粘性会话,每个就拿到稳定、独立的住宅 IP——会话串怎么用见 什么是轮换代理。
Puppeteer
Puppeteer 把代理作为 Chromium 启动参数,认证在页面上处理。凭据不放进参数:
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch({
args: ['--proxy-server=http://gw.roamproxy.com:41080'],
});
const page = await browser.newPage();
await page.authenticate({ username: 'YOUR_USERNAME', password: 'YOUR_PASSWORD' });
await page.goto('https://ip.sb');
console.log(await page.evaluate(() => document.body.innerText));
await browser.close();
Puppeteer 把代理作用于整个浏览器,所以要同时跑多个 IP,就启动多个浏览器(各带自己的 --proxy-server 和粘性会话),或在前面放代理路由。
验证出口
上面两段都会导航到 IP 检测接口并打印结果。它应显示 Roam 住宅出口 IP 和你选的国家,而不是你机器的真实地址。若显示真实 IP,说明代理没挂上——回看 常见问题。
不需要浏览器的时候
目标站需要 JavaScript 或交互式挑战时,Playwright 和 Puppeteer 是对的工具。不需要时——纯 JSON API 或静态 HTML——完整浏览器就太慢太重了。要给脚本式 HTTP 请求配浏览器级指纹,改用 curl_cffi;按防护层级在两者间怎么选,见 网页采集如何过 Cloudflare。用 LLM 驱动 Playwright,见 browser-use 配住宅代理。
常见问题
代理该设在 launch 还是 context 上?
Playwright 里优先设在 context。设在 launch() 上是整个浏览器用一个代理;设在 new_context() 上让每个 context 有各自的代理——一个脚本跑多个身份时正需要这个,每个 context 成为独立浏览器会话、独立 IP。Puppeteer 没有一等的 per-context 代理,要多 IP 就启动多个浏览器,或在前面放一个代理路由。
用户名密码怎么传?
Playwright 里把它们作为 username 和 password 放进 proxy dict,和 server 并列——绝不要塞进 server URL。Puppeteer 里凭据不放 args;在 args 里设 --proxy-server=主机:端口,然后在第一次导航前调 await page.authenticate({username, password})。
已经用真实浏览器了,还需要 curl_cffi 吗?
不需要——用浏览器的意义就在这。Playwright 和 Puppeteer 驱动真实 Chromium,TLS/JS 指纹本来就是真的。curl_cffi 是给不用浏览器的脚本式 HTTP 请求补回那个指纹的。用 Playwright/Puppeteer 你只需修网络层,那正是代理的活。
浏览器起来了却还是显示真实 IP,为什么?
通常是代理设在了错的对象上,或凭据被塞进了 server URL。确认 server 是纯 http://主机:端口,username/password 是独立键(Playwright)或通过 page.authenticate() 设(Puppeteer),并且代理挂在了你实际导航用的 context/浏览器上。然后重跑下面的 IP 检测。
两个框架都要一个纯 主机:端口 代理加凭据——正是 Roam 给你的。轮换住宅 $2/GB、静态住宅 $4/IP/月,HTTP 与 SOCKS5 都支持。注册账号即送 300MB 试用流量,让你第一个浏览器从住宅出口跑起来。