如果你在为通过住宅代理运行的工作在 Selenium 和 Playwright 之间做选择,或者两者都在维护,真正有用的不是两份独立的搭建指南,而是对比:哪些是相同的,哪些是真正不同的,以及这些差异中哪些应该影响你的构建方式。下面是同一项工作在两者中的做法,并排呈现。
关于每个框架更深入的细节,包括各自的边界情况,请参阅 Selenium 中的住宅代理 和 Playwright 中的住宅代理。本文是在此之上的对比层。
相同之处:网关
两个框架都以相同的用户名和凭据与同一个端点通信,因为代理并不关心是谁在驱动它。主机 p.shifter.io,端口 443,所有的定向设置都编码在用户名中:
customer-USERNAME # rotate, no geo
customer-USERNAME-country-de # German exit
customer-USERNAME-country-us-city-new_york # city level
customer-USERNAME-country-de-sid-abc123-ttl-600 # sticky, ten minutes
这意味着关于地理位置、轮换和会话生命周期的每一项决定都只是一个字符串,在两个框架中都是相同的。下面各节的内容都不会改变网关本身,只会改变每个框架把凭据传给它的方式。格式参考见 如何连接。
唯一真正的差异:身份验证
这是真正重要的差异,也解释了大多数人遇到摩擦的原因。
Playwright 原生支持带身份验证的代理。 用户名和密码是一等选项,因此开箱即用。
Selenium 则不支持。 它可以设置代理主机和端口,但 WebDriver 规范没有传递凭据的机制,因此 Chrome 会弹出一个原生的身份验证对话框,你的脚本无法关闭它。每一种 Selenium 的解决方案都是针对这个缺口的变通办法,共有三种:Selenium Wire,它替你处理凭据;一个生成的小型 Chrome 扩展,用来提供凭据;或者 CDP,直接驱动浏览器的调试协议。
如果你是从零开始,且工作需要带身份验证的代理,仅这一项差异就是选择 Playwright 的正当理由。
两者中相同的搭建方式
Playwright,Python:
from playwright.sync_api import sync_playwright
USER = "customer-USERNAME-country-de-sid-abc123-ttl-600"
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context(
proxy={"server": "http://p.shifter.io:443",
"username": USER, "password": "PASSWORD"},
locale="de-DE", timezone_id="Europe/Berlin", # match the exit
)
page = context.new_page()
page.goto("https://ipinfo.io/json")
print(page.inner_text("body"))
Playwright,Node:
const ctx = await browser.newContext({
proxy: { server: 'http://p.shifter.io:443',
username: 'customer-USERNAME-country-de-sid-abc123-ttl-600',
password: 'PASSWORD' },
locale: 'de-DE', timezoneId: 'Europe/Berlin',
});
Selenium,Python,使用 Selenium Wire:
from seleniumwire import webdriver
USER = "customer-USERNAME-country-de-sid-abc123-ttl-600"
proxy_url = f"http://{USER}:PASSWORD@p.shifter.io:443"
opts = {"proxy": {"http": proxy_url, "https": proxy_url,
"no_proxy": "localhost,127.0.0.1"}}
driver = webdriver.Chrome(seleniumwire_options=opts)
driver.get("https://ipinfo.io/json")
print(driver.find_element("tag name", "body").text)
同样的网关,同样的用户名,同样的结果。唯一的区别在于凭据是如何传进去的。
结构性差异:如何隔离身份
这才是真正应该影响你设计方式的差异,它源于在每个框架中隔离一个身份的成本高低。
在 Playwright 中,context 是廉价的。 一个浏览器 context 就是一个独立的配置文件,拥有自己的 cookie、存储,重要的是,还有自己的代理。你可以只运行一个浏览器进程,为每个身份创建一个 context,这使得轮换地理位置或会话变成创建新 context 而不是新浏览器的问题。
browser = p.chromium.launch() # one process
for country in ["de", "fr", "us"]:
ctx = browser.new_context(proxy={"server": "http://p.shifter.io:443",
"username": f"customer-USERNAME-country-{country}",
"password": "PASSWORD"})
page = ctx.new_page()
page.goto("https://example.com")
ctx.close() # identity discarded, process stays
在 Selenium 中,代理是绑定在 driver 上的。 更改代理通常意味着需要一个新的 driver,而一个 driver 就是一整个浏览器进程:启动慢、内存占用大。因此 Selenium 的模式恰恰相反,对一个身份复用一个 driver 来处理许多请求,把身份的更换当作一项昂贵的操作,围绕它做批处理,而不是逐请求进行。
实际的结果是:需要许多短生命周期身份的工作在 Playwright 中明显更便宜,而长时间持有一个身份进行长序列操作的工作,两者都适用。如果你在运行 Selenium 时发现自己在为每个请求启动一个 driver,那才是首先要解决的问题,而不是代理配置。
地理位置、轮换与会话
由于定向设置在用户名中,这部分与框架无关。省略 sid 每次新连接都会获得一个新的出口地址;包含它则相同的地址会一直保持,直到 TTL 到期。在 Playwright 中你按 context 来限定范围;在 Selenium 中你按 driver 来限定范围。
在两者中都要做对的一件事:当你设置了国家时,要让浏览器的语言区域和时区与之匹配。一个报告纽约时区的德国出口地址是一个容易被检测、也容易避免的矛盾,两个框架都将这些作为 context 选项暴露出来,详见 匹配代理的地理位置、时区和语言区域。
带宽:两个框架共同的成本
浏览器在按 GB 计费的产品上开销很大,因为它们会抓取真实浏览器会获取的一切:图片、字体、媒体、分析脚本。屏蔽不需要的内容是可获得的最大单项节省,两个框架都支持这一点。
Playwright:
context.route("**/*", lambda route: route.abort()
if route.request.resource_type in {"image", "media", "font", "stylesheet"}
else route.continue_())
Selenium 在原生形式下没有对应的一行代码写法;使用 Selenium Wire 你可以过滤请求,或者通过 CDP 屏蔽资源类型。无论哪种方式都值得去做,因为它通常能将页面体积削减到原来的一小部分。更广泛的讨论,包括你是否真的需要浏览器,见 何时需要无头浏览器 和 降低代理带宽成本。
在两者中验证是否生效
不要假设代理已经生效。导航到一个能报告地址的端点,检查它不是你自己的地址:
# Playwright
page.goto("https://ipinfo.io/json"); print(page.inner_text("body"))
# Selenium
driver.get("https://ipinfo.io/json"); print(driver.find_element("tag name", "body").text)
如果地址是你自己的,说明代理根本没有生效。如果地址正确但内容不符合该地区的预期,先怀疑 DNS 或语言区域不匹配,而不是先怀疑代理池,详见 防止 DNS 泄漏。
如何选择
如果你没有任何既有的技术承诺,并且工作涉及带身份验证的代理和许多身份,Playwright 是更轻松的路径:原生的凭据支持和廉价的按 context 隔离,消除了两个原本需要你花力气去解决的问题。
在你已经拥有 Selenium 技术栈、需要它的 grid 和跨浏览器生态系统,或者工作是一个长生命周期的会话而不是许多短会话的场景下,Selenium 仍然是合理的选择。它对代理的支持完全可行,只是需要一个库或一个小扩展来传入凭据。
而在这两种情况下都要记住,浏览器只是避免被封的一半:地址能让你到达门口,而请求头、指纹和节奏决定接下来会发生什么,详见 避免被封。
结论
两个框架的网关是相同的,所以地理位置、轮换和会话生命周期在两者中都是同一个字符串。真正的差异在于身份验证,Playwright 原生支持,而 Selenium 不支持,需要 Selenium Wire、扩展或 CDP。应该影响你架构的差异是隔离成本:Playwright 的 context 很廉价,所以你按 context 轮换身份;而 Selenium 的代理绑定在 driver 上,所以你复用 driver 并批量处理身份更换。在两者中都要把语言区域和时区与出口地址相匹配,在两者中都要屏蔽不必要的资源,因为你是按 GB 付费的,并且在信任任何结果之前先验证出口地址。
两者都运行在同一套 住宅代理 之上,一个具备国家和城市定向及需要时可用粘性会话的网关,按 每 GB 计费,因此上述的资源屏蔽会直接转化为更低的账单。