关于 playwright-bot-bypass
Playwright Bot Bypass 是用于获准测试的浏览器自动化技能,借助 rebrowser-playwright 和有头模式下的真实 Chrome 减少部分自动化检测信号。面向网站所有者的 QA、无障碍测试和研究;不保证绕过行为或 IP 检测,也不自动通过 CAPTCHA。
主要功能
- 01基于 rebrowser-playwright
- 02使用有头真实 Chrome
- 03移除部分 Playwright 标记
- 04提供浏览器工厂模板
- 05包含检测测试脚本
适用场景
- 01对自有网站进行自动化 QA
- 02测试网页无障碍表现
- 03研究浏览器自动化检测
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ greekr4/ playwright-bot-bypass --skill playwright-bot-bypass安装后在 Claude Code 中输入/playwright-bot-bypass确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
.gitignorepackage-lock.jsonpackage.jsonexamples/ab-test.mjsstealth-google-search.mjsstealth-twitter-scrape.mjsscripts/bot-detection-test.mjsstealth-template.mjs详细介绍
Playwright Bot Bypass
借助 rebrowser-playwright 和真实的有头模式 Chrome 降低被检测为机器人的风险。可通过指纹检测网站(bot.sannysoft.com、areyouheadless)的检查,并避免在 Google 上触发 CAPTCHA。不保证能够绕过能感知 CDP/运行时的企业级机器人管理系统——实测结果请参阅“检测覆盖范围”。
仅限授权用途。 本工具用于对你拥有或获准测试的网站进行 QA、无障碍测试和研究。请遵守各网站的服务条款、
robots.txt和适用法律。请勿使用本工具绕过付费墙、滥用速率限制,或违背网站明确意愿进行抓取。
如何绕过检测(以及各层的作用)
规避检测依赖三层措施,而非单一手段——其中大部分来自真实浏览器,而非手写的 JS:
| 检测点 | 标准 Playwright(无头模式) | 绕过方式 |
|---|---|---|
CDP / Runtime.enable 泄漏 | 存在(无头模式特征) | rebrowser + REBROWSER_PATCHES_RUNTIME_FIX_MODE(自动设置) |
window.__pwInitScripts(isPlaywright) | 存在 | 清除残留(初始化脚本会在每次导航时删除它) |
navigator.webdriver | true | rebrowser(报告为 false;我们不会删除它——undefined 本身就是一种特征) |
| WebGL 渲染器 | SwiftShader(软件渲染) | channel:'chrome' + 有头模式(真实 GPU) |
| User Agent | 包含 "HeadlessChrome" | channel:'chrome'(真实 Chrome UA)——不使用 JS 覆盖 |
| Canvas 指纹 | 软件渲染特征 | 有头模式下的真实 Chrome(真实 GPU canvas)——不添加 JS 干扰 |
navigator.plugins | 空数组 | 有头模式下的真实 Chrome(真实 PluginArray)——不使用 JS 伪造 |
navigator.languages | 仅有 ['en-US'] | locale 选项(原生设置,与 worker 一致——不使用 JS getter) |
为什么只写这么少 JS? 在 v2.1/v2.2 中,旧版的 fake-PluginArray、canvas-noise、硬编码的
hardwareConcurrency、permissions-override、删除webdriver,以及navigator.languagesgetter 均已移除——这些做法都会造成可检测的不一致(自有属性特征、worker 不匹配、webdriver为undefined、Illegal invocation崩溃)。v2.2 只保留两项启用中的措施:清除 Playwright 的__pwInitScripts残留,并启用 rebrowser 的 Runtime-fix。其余一切都由真实且自洽的浏览器处理。伪造越少 = 一致性越高 = 越难检测。
前提条件
- Node.js 18+,支持 ESM(
.mjs文件) - 已安装 Google Chrome(不只是 Chromium)
- 必须使用有头模式(
headless: false)——没有显示环境就无法隐蔽运行
验证 Chrome 是否已安装:
# macOS
/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --version
# Windows
"C:\Program Files\Google\Chrome\Application\chrome.exe" --version
# Linux
google-chrome --version
快速开始
1. 安装
npm init -y && npm install rebrowser-playwright
2. 创建 stealth-test.mjs
import os from 'node:os';
import path from 'node:path';
// Enable rebrowser's Runtime.enable fix BEFORE importing the library.
process.env.REBROWSER_PATCHES_RUNTIME_FIX_MODE ??= 'addBinding';
const { chromium } = await import('rebrowser-playwright');
const browser = await chromium.launch({
headless: false, // headed = real GPU/canvas
channel: 'chrome', // real Chrome = real UA/WebGL/plugins
args: ['--disable-blink-features=AutomationControlled']
});
// `locale` sets navigator.languages + Accept-Language natively & consistently.
const context = await browser.newContext({ locale: 'ko-KR' });
// The ONLY init script: strip Playwright's main-world signature. Touch NOTHING
// on navigator — the real browser's values are already genuine & consistent.
await context.addInitScript(() => {
for (const k of Object.getOwnPropertyNames(window)) {
if (/^__pw|pwInitScripts|playwright/i.test(k)) {
try { delete window[k]; } catch {}
}
}
if (!window.chrome) window.chrome = {};
});
const page = await context.newPage();
try {
await page.goto('https://bot.sannysoft.com', { waitUntil: 'networkidle' });
const out = path.join(os.tmpdir(), 'stealth-test.png');
await page.screenshot({ path: out });
console.log(`Screenshot saved: ${out}`);
} finally {
await browser.close();
}
3. 运行
node stealth-test.mjs
使用模板(推荐)
scripts/stealth-template.mjs 提供了一个可复用的工厂函数,其中已预先应用所有补丁:
import { createStealthBrowser, humanDelay, humanType, simulateMouseMovement } from './scripts/stealth-template.mjs';
const { browser, page } = await createStealthBrowser();
try {
await page.goto('https://example.com');
// Human-like mouse movement (avoids Cloudflare Turnstile)
await simulateMouseMovement(page);
// Human-like typing instead of instant fill
await humanType(page, 'input[name="q"]', 'search query');
await humanDelay(300, 800);
} finally {
await browser.close();
}
模板选项
const { browser, context, page } = await createStealthBrowser({
headless: false, // Required for stealth (default)
viewport: { width: 1280, height: 800 }, // Default
locale: 'ko-KR', // Browser locale (default)
userAgent: null, // Custom UA (optional; default = real Chrome UA)
storageState: './session.json', // Cookie persistence (optional)
proxy: { server: 'http://proxy:8080' }, // Proxy (optional)
noSandbox: false // Opt-in --no-sandbox (Linux root/CI only; it's a bot signal)
});
// Save session for reuse
import { saveSession } from './scripts/stealth-template.mjs';
await saveSession(context, './session.json');
模板的实际作用
该模板(v2.2)将生效范围严格限制为两项措施:
| 措施 | 原因 |
|---|---|
移除 window.__pwInitScripts / __playwright*(初始化脚本,每次导航时执行) | 移除 isPlaywright 确定性特征检测器所依赖的标记 |
REBROWSER_PATCHES_RUNTIME_FIX_MODE=addBinding(导入前自动设置) | 隐藏 CDP Runtime.enable 暴露的无头浏览器特征 |
它对 navigator 毫不改动。其余一切都交由真实浏览器处理(channel:'chrome' + 有头模式):真实的 User-Agent、WebGL/GPU 渲染器、Canvas 指纹、PluginArray、自洽的权限/硬件值,以及(通过 locale 选项)与原生 Worker 一致的 navigator.languages + Accept-Language。
v2.1/v2.2 中移除的内容(每项都会产生负面影响,因为伪造的值与真实环境不一致):伪造的 navigator.plugins、Canvas getImageData 噪声、硬编码的 hardwareConcurrency/deviceMemory、outerWidth/Height 偏移、权限覆盖(因 Illegal invocation 而崩溃)、删除 navigator.webdriver(使其变为 undefined,反而暴露特征),以及 navigator.languages getter(会暴露自身属性 + Worker 不匹配特征)。
启动参数:--disable-blink-features=AutomationControlled。--no-sandbox 为可选启用({ noSandbox: true })——它既有安全风险,也是自动化信号,因此默认关闭。
在
addBinding模式下,复杂的 SPA(TikTok/IG/FB)可能会输出非致命的[rebrowser-patches] cannot get world警告,但页面仍会加载。如有需要,可切换到REBROWSER_PATCHES_RUNTIME_FIX_MODE=alwaysIsolated以消除这些警告。
脚本
scripts/stealth-template.mjs— 可复用的隐身浏览器工厂(所有示例都从此处导入)scripts/bot-detection-test.mjs— 在 bot.sannysoft.com 验证绕过效果
示例
examples/stealth-google-search.mjs— 无需 CAPTCHA 的 Google 搜索examples/ab-test.mjs— 并排对比检测模式与隐身模式examples/stealth-twitter-scrape.mjs— 抓取 Twitter/X 个人资料
注意:
ab-test.mjs同时需要rebrowser-playwright和playwright:npm install rebrowser-playwright playwright && npx playwright install chromium
所有屏幕截图都会保存到操作系统的临时目录(os.tmpdir())——macOS/Linux 上为 /tmp,Windows 上为 %TEMP%。
检测覆盖情况(测量日期:2026-06-10,macOS 有头 Chrome,v2.2)
如实报告的测试结果。v2.2 的特征清理 + Runtime 修复使所有指纹/自动化检测器均显示通过:
| 检测器 | 结果 | 备注 |
|---|---|---|
| bot.sannysoft.com | ✅ 全部绿色 | webdriver 为 false,WebGL/UA/plugins 均为真实值 |
| arh.antoinevastel.com/bots/areyouheadless | ✅ “not Chrome headless” | |
| hmaker.github.io/selenium-detector | ✅ “Passing” | 没有 chromedriver |
| bot-detector.rebrowser.net | ✅ 0 个红色项 | 已移除 __pwInitScripts,无 Runtime 泄露,webdriver 为 false |
| deviceandbrowserinfo.com/are_you_a_bot | ✅ “You are human!” | isBot:false,isPlaywright:false |
| browserscan.net/bot-detection | ✅ “Normal” | CDP 测试通过(Runtime 修复) |
| iphey.com | ✅ “Trustworthy” | v2.2 之前显示为“Unreliable” |
| creepjs | ✅ 无无头浏览器特征 / 无隐身特征 | 模糊的“38% like headless”不属于检测结果 |
| nowsecure.nl(Cloudflare Turnstile) | ⚠️ 显示交互式验证 | 行为/IP 门槛,不是指纹检查;无法自动通过 |
可靠性:重复运行 9/9 次均正常(__pwInitScripts 清理在每次导航中均有效)。
v2.2 如何实现这一点(以及它无法修复的一点)
通过 createStealthBrowser() 内置的两个手段:
- 清除特征 — 初始化脚本会在每次导航时删除
window.__pwInitScripts/__playwright*(确定性的isPlaywright特征)。 REBROWSER_PATCHES_RUNTIME_FIX_MODE=addBinding— 在导入前自动设置;隐藏 CDPRuntime.enable泄漏。
残留泄漏:window.__playwright_builtins__ 是另一个独立的、不可配置的 Playwright 全局变量,无法删除或重新定义。目前上述检测器都不会针对它进行检测,但未来的检测器可能会。没有任何 rebrowser 版本(你使用的是最新的 1.52.0)能将其移除——该问题已在上游 rebrowser-patches#110 跟踪,目前仍未解决。
要点:可有效应对指纹和自动化框架检测。但仍不能保证绕过基于行为/IP 的系统(Cloudflare Turnstile、DataDome、Kasada)或登录墙。要应对这些情况,请添加住宅 IP 并进行真实交互,或切换引擎——patchright(可直接替换)或 nodriver(从结构上避开整个 CDP/自动化协议类别)。
真实社区网站(未登录状态下单次加载、住宅 IP、2026-06-10)
测试 v2.2 页面加载是否会被真实网站拦截为机器人(不是判断能否登录):
| 网站 | 结果 |
|---|---|
| Reddit、YouTube、Pinterest、Threads、X(直接 URL)、Quora、TikTok | 🟢 内容完整加载——无机器人验证、无 CAPTCHA |
| Instagram、Facebook、LinkedIn | 🟡 内容框架加载,但被标准的未登录登录弹窗遮挡——不是机器人拦截 / 验证页 / HTTP 999 |
**关键结果:**没有任何网站返回机器人验证或强硬拦截。最“难搞”的网站(IG/FB/LinkedIn)提供的是正常的未登录用户体验(在可见内容上方显示登录弹窗),这意味着隐身模式通过了检测,被视为真实用户。**注意:**每个网站都只在干净的住宅 IP 上加载了一次。大量访问时,IG/FB/LinkedIn 会执行 datr Cookie 老化、HTTP 999 和速率限制——这些是 IP/账号问题,而非指纹问题,本技能无法解决。TikTok 的签名 API 操作(查看个人资料之外的操作)也仍需要预热过的会话。
限制
- 需要
headless: false(带显示器的有头模式) - 需要安装真正的 Google Chrome(
channel: 'chrome') - 某些网站仍可能根据行为模式进行检测——请使用
humanDelay、humanType、simulateMouseMovement - 不会绕过 CAPTCHA,只会避免触发 CAPTCHA
- TLS/JA3 指纹由
channel: 'chrome'处理(使用真正的 Chrome 二进制文件) __pwInitScripts泄漏(参见检测覆盖范围)无法在技能层面修复——这是 rebrowser-playwright 1.52.0 固有的问题
Python 支持
undetected-chromedriver(推荐)
pip install undetected-chromedriver
import undetected_chromedriver as uc
# Match your Chrome version: check chrome://version
driver = uc.Chrome() # auto-detects version
driver.get("https://www.google.com")
search_box = driver.find_element("name", "q")
search_box.send_keys("your search query")
search_box.submit()
Python
playwright-stealth只在 JS 层面进行修补——WebGL 仍会显示 SwiftShader。请改用undetected-chromedriver。
替代方案:从 Python 调用 Node.js
import subprocess
result = subprocess.run(['node', 'stealth-script.mjs', query], capture_output=True)
故障排除
| 问题 | 修复方法 |
|---|---|
ERR_MODULE_NOT_FOUND | 在脚本所在目录运行 npm install rebrowser-playwright |
| 浏览器无法打开 | 确认已安装 Chrome(参见先决条件) |
| WebGL 显示 SwiftShader | 实际上你处于无头模式 / 没有 GPU。请在有真实 GPU 的机器上使用 channel: 'chrome' 运行有头模式(headless: false);SwiftShader 是软件回退方案,而非导入问题 |
| 仍被检测到 | 在操作之间添加 simulateMouseMovement() 和 humanDelay() |
| 进程挂起 | 确保 browser.close() 位于 finally 块中 |
SyntaxError: await | 文件必须是 .mjs,或在 package.json 中设置 "type": "module" |