rebrowser_playwright 实测:一行 import 没改,Playwright 脚本绕过知乎反爬
我遇到了什么问题
我在写一个多平台内容发布系统,其中知乎发布模块用 Playwright 做浏览器自动化。代码写完第一天就跑通了------登录、写回答、点发布,一切正常。
第二天再跑,知乎直接跳验证码。第三天连验证码都不给了,直接白屏。
同一个脚本、同一个 user_data_dir,什么都没变,就是突然不能用了。我排查了一整天,最后定位到一件事:知乎检测到了 Playwright 的自动化特征,触发了反爬。
如果你在用 Playwright 做任何国内网站的自动化,你大概率已经踩过或者即将踩这个坑。
我试过的方案
方案 A:加 stealth 插件
pip install playwright-stealth,然后在代码里加两行:
python
from playwright_stealth import stealth_sync
stealth_sync(page)
结果:知乎有改善------从"直接白屏"变成了"偶尔能加载但频繁弹验证码"。Stealth 藏了 webdriver 标记,但 Chromium 源码里还有几十处指纹点,光靠 JS 注入藏不完。
这个方案我保留着作为辅助层,但单靠它不够。
方案 B:用 rebrowser_playwright 替换 playwright
rebrowser_playwright 是社区维护的 Playwright 分支,直接改了 Chromium 源码层的指纹点,不是 JS 打补丁。安装后 API 完全兼容------把 from playwright.sync_api 改成 from rebrowser_playwright.sync_api,其余代码不动。
python
# 之前
from playwright.sync_api import sync_playwright
# 之后
from rebrowser_playwright.sync_api import sync_playwright
结果:同一套业务代码,只改了一行 import,知乎从"必弹验证码"变成"零拦截"。我连续跑了三周,没再触发过反爬。
核心代码
完整的知乎发布上下文启动代码(简化自真实项目):
python
# zhihu_publisher.py --- launch_persistent_context 配置
_CHROME_ARGS = [
"--disable-blink-features=AutomationControlled",
"--disable-features=IsolateOrigins,site-per-process",
"--no-sandbox",
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-infobars",
"--disable-breakpad",
"--disable-component-extensions-with-background-pages",
]
_CONTEXT_SETTINGS = {
"viewport": {"width": 1440, "height": 900},
"timezone_id": "Asia/Shanghai",
"locale": "zh-CN",
"user_agent": (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/124.0.0.0 Safari/537.36"
),
}
def _launch_context(self, playwright):
kwargs = {
"user_data_dir": self.user_data_dir, # 持久化登录态
"headless": False,
"args": _CHROME_ARGS,
**_CONTEXT_SETTINGS,
}
context = playwright.chromium.launch_persistent_context(**kwargs)
if self.storage_state.exists():
state = json.loads(self.storage_state.read_text())
context.add_cookies(state.get("cookies", []))
return context
关键参数解释:
user_data_dir:持久化存储,登录态不丢。不用每次启动重新登录,也避免了新号频繁登录触发风控。这一行比任何 stealth 技巧都重要。--disable-blink-features=AutomationControlled:关掉 Chromium 自动在navigator.webdriver上打的标记。普通 Playwright 即使设headless=False,这个标记也在。locale+timezone_id:模拟中国用户环境。国内网站对非中文 locale 的请求更敏感。headless=False:有头模式。知乎对 headless Chromium 有专门的检测规则,即使是 rebrowser 也建议有头跑。
附加:每页注入的反检测脚本
rebrowser 解决了源码层,但有些检测点靠 JS 注入更灵活:
javascript
// 注入到每个页面的反检测脚本
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
// 伪造 Chrome 插件列表(真实 Chrome 有 4-5 个内置插件)
Object.defineProperty(navigator, 'plugins', {
get: () => {
const plugins = [
{ name: 'Chrome PDF Plugin', ... },
{ name: 'Chrome PDF Viewer', ... },
{ name: 'Native Client', ... },
];
Object.setPrototypeOf(plugins, PluginArray.prototype);
return plugins;
}
});
// 伪造硬件信息
Object.defineProperty(navigator, 'hardwareConcurrency', { get: () => 8 });
Object.defineProperty(navigator, 'deviceMemory', { get: () => 8 });
这段代码每次 page.add_init_script() 注入。rebrowser 已经把大部分指纹改了,但 navigator.plugins 和 navigator.hardwareConcurrency 这两个点浏览器指纹差异很大,手动伪造更可控。
踩坑记录
坑 1:launch_persistent_context 的 user_data_dir 路径用反斜杠
Windows 下路径写 C:\data\zhihu 会报错。Playwright 内部用 / 分隔路径,Windows 传 C:\\ 会解析异常。改成 C:/data/zhihu 或 Path 对象转换:
python
# 报错
user_data_dir = "C:\\Users\\admin\\.browser-data\\zhihu"
# 正常
user_data_dir = str(Path(".browser-data") / "zhihu")
这个坑折腾了我一个下午------报错信息是 Target closed,完全看不出来是路径问题。
坑 2:headless=True 加 rebrowser 还是会被知乎检测
我以为 rebrowser 改了源码层指纹,headless 也能过。结果页面加载后直接报 405 错误,或者无声崩掉------没有报错信息,但页面就是空白。查了才发现知乎对 headless 有单独的检测规则(Canvas 渲染差异、字体渲染差异),rebrowser 也没有完全消除这些差异。修复方法就是把 headless 改成 False------一行配置,问题消失。
坑 3:发布按钮 button:has-text("发布") 误匹配
知乎编辑器里有不止一个含"发布"二字的按钮------"发布回答""发布设置"。用 button:has-text("发布") 会匹配到两个,Playwright 点第一个(可能是"发布设置"而不是"发布回答")。结果是点了半天文章发不出去,页面也没有任何报错,就是不动。
修复方案:放弃 Playwright 选择器,用 JS 精准匹配按钮文本:
python
# 坏
page.locator('button:has-text("发布")').click()
# 好
page.evaluate("""() => {
var btns = document.querySelectorAll('button');
for (var i = 0; i < btns.length; i++) {
if (btns[i].textContent.includes('发布回答')) {
btns[i].click();
}
}
}""")
JS 兜底比 Playwright 选择器稳定------不会被 CSS 伪装干扰,也不受元素可见性判断误差影响。
总结
用 Playwright 做国内网站自动化,核心就两条:
rebrowser_playwright替换原生 Playwright。import 改一行,API 不变,反爬通过率从 0 拉到 90%。launch_persistent_context+user_data_dir。持久化登录态,越像真人浏览器越不容易触发风控。
剩下的 stealth JS、Chrome args、环境伪装属于锦上添花------主菜是 rebrowser 和持久化上下文。
如果你有类似需求,可以先试着只改一行 import 看效果。多数情况下这一行就够了。
代码来源:项目 zhihu_publisher.py,完整代码可在项目仓库查看。 运行环境:Windows 11, Python 3.10, rebrowser_playwright, Chrome 124