- 人工智能
- AI Agent
- 浏览器控制
- GUI 自动化
- MCP 服务
【免费下载链接】invisible_playwright_mcp
Playwright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.
在服务器上跑 browser-use 的 AI 代理经常遇到同一个场景:笔记本上一切正常,一上服务器就撞上验证码或 challenge 页。问题通常不在代理本身,也不在 prompt,而在它驱动的浏览器和那台机器——而这两者里,只有一小部分能从配置文件里碰到。这篇文章以BrowserProfile为线索,逐项说明哪些配置真的有用、哪些配置永远够不到、agent 会话独有的"节奏"信号长什么样,以及想换掉 Chromium 引擎时唯一走得通的 MCP 路线——这条路线正是本仓库invisible_playwright_mcp所基于的实现。读完你会得到一套完整的排查顺序:先分清问题属于哪一堆,再决定是调配置、换机器,还是换引擎。
说明:文中关于 browser-use 的细节(
BrowserProfile字段、Chromium-only 的channel、cdp_url、默认自动化掩码参数)均按原文档记录,作者曾于 2026-09-03 对照browser_use/browser/profile.py复核;关于本仓库引擎、MCP 服务器与配置变量的部分,则以当前仓库源码为准。
一、先分清:被拦的往往不是 agent,也不是 prompt
browser-use 的代理在本地跑得好好的,部署到服务器就收到 challenge 页,最常见的原因是:代理在两边是同一个,机器不是同一个。浏览器是代理开的那台浏览器,但它运行在什么样的 GPU、字体、音频、屏幕和网络栈之上,是另一回事。任何 agent 框架都改变不了机器级的事实,浏览器-use 也不例外。
这篇文章就是把这堆事情分好类:BrowserProfile实际暴露了什么,哪些设置值得用,哪些设置什么都够不到,什么信号是 agent 驱动的会话特有的,以及"换一个引擎"这个问题的诚实答案。
二、BrowserProfile:browser-use 给的全部可调旋钮
BrowserProfile是 browser-use 的配置面:一份交给浏览器会话的启动参数与上下文参数模板。与拦截相关的字段如下:
| 字段 | 作用 |
|---|---|
executable_path | 启动哪个浏览器二进制——文档上注明为 Chromium 系可执行文件 |
channel | Chromium 频道:chromium、chrome、beta/dev/canary 变体、Edge 变体 |
user_data_dir | 持久化 profile 目录 |
proxy | 代理设置(server、bypass、用户名、密码) |
headless | 无头还是有头 |
args | 附加命令行参数 |
cdp_url | 通过 CDP 连接一个已在运行的浏览器,而不是启动一个新的 |
这确实是一组真实可用的杠杆,其中两个比大多数人用得更有价值:executable_path和user_data_dir。
2.1 把executable_path指向你真实的 Chrome
这个字段期望的是 Chromium 家族浏览器——channel枚举里的每一个值都是 Chromium、Chrome 或 Edge,没有 Firefox。它的实际用途是把你已安装的 Chrome 指进来,而不是用随包附带的测试用 Chromium。
两者不是同一个浏览器:编解码器集合不同、品牌标识不同,而一个真实安装的 Chrome 是远比捆绑构建常见得多的"事物"。对检测来说,一个"真实存在的桌面浏览器"和"一个自动化项目捆绑的构建产物"是两个不同的指纹。
2.2 给user_data_dir一个"过去"
把user_data_dir指向一个真正用过的 profile 目录,是这份配置里价值最高的单项改动,因为它是唯一一个针对"历史"而不是针对"硬件"的设置。一个从空 profile 起步的代理,就是一个哪儿都没去过的浏览器——"全新浏览器得分低"的大部分原因就在这里。
两个陷阱必须先知道:
- profile 锁死(profile lock-in):一旦 profile 目录被浏览器占用,重复启动同一个目录可能因锁而失败;
- 身份一致性:profile 必须搭配一个一致的身份来使用——换个说法,一个登录状态被另一套"硬件指纹"(不同的种子/指纹)承载,和换台电脑登录一样显眼。
值得一提的是,本仓库在身份一致性上走得更远:在invisible_playwright_mcp的 MCP 服务器里,身份由seed决定(同一个 seed 永远是同一个指纹),而profile 目录自己拥有它的 seed——首次在新 profile 上打开浏览器时会把这个身份写进 profile,之后每次打开都复用同一个,所以"登录不会穿不同的硬件回来"。如果你显式要求的 seed 与 profile 携带的 seed 冲突,服务器会直接拒绝并同时报出两个数字,绝不会悄悄替你选一个(见 配置解析实现 与 MCP 服务器文档 中关于 seed 与 profile 的说明)。
2.3 别高估默认的自动化掩码
browser-use 的默认启动参数里已经带了自动化掩码:--disable-blink-features=AutomationControlled及相关 flag。它掩盖的是最粗糙的驱动标记,属于表面功夫,对下一节列出的任何一项都毫无作用。不要把"掩码存在"当成"指纹干净"。
三、没有任何配置够得到的东西:机器级六项
BrowserProfile的任何一个字段都改不了下面这些——它们全部是"机器"的属性,而在服务器上它们会同时成立:
- 没有 GPU:WebGL 上报的是软件渲染器;
- 容器字体集:与所声称的操作平台对不上;
- 没有音频设备:音频相关取值回落到默认值;
- 没有任务栏的屏幕:分辨率是默认值;
- 编解码器支持:描述的是一个精简构建,而不是桌面安装;
- TLS 握手:由网络栈决定,发生在任何页面级设置存在之前。
这正是"笔记本上能跑、Docker 里被拦"成为最常见问题形态的原因:代理在两个地方完全一样,机器不一样。
换个角度理解:指纹是一张照片,行为是一段动作研究。把照片修得完美,不会让动作研究变好。本仓库的引擎(invisible_playwright,一个在 C++ 层面打过补丁的 Firefox)的职责就是"照片"这一层:渲染、驱动表面、网络握手都读起来像真正的 Firefox。它真实,而且覆盖了大部分拦截原因;但它不是全部,这个边界必须诚实——引擎控制的是浏览器"是什么",而不是它上方的循环"以什么节奏决定行动"。节奏由模型和调用模型的 harness 产生,在浏览器之上、引擎够不到的地方。
四、agent 会话特有的信号:think-act 节奏
browser-use 会话(以及所有 LLM 代理会话)携带一个普通爬虫没有的信号:think-act 循环的节奏。代理读页面、调模型、等待、再行动,于是它的行为模式与人有四点显著不同:
- 间隙聚簇:动作之间的等待围绕模型推理延迟聚拢,步复一步、轮复一轮——人的停顿散布得又宽又参差(这里一秒一瞥,那里八秒一读)。单个数字不是信号,分布的形态才是;
- 停顿中的静止:人读页面时会漂移指针、微滚页面、悬停;代理的指针在停顿期间纹丝不动,然后精准到达目标;
- 动作瞬间落在正中心:坐标来自页面结构或截图,落在目标中心,没有接近、没有过冲、没有修正、点击前没有阅读时间;
- 没有浪费的动作:人会滚过头、开错标签、悬停在从不点击的东西上、改变主意;代理只执行任务需要的动作,高效且可见。
没有任何框架的 stealth 设置能修复这个信号,因为它产生在浏览器之上。这一信号的完整剖析见 AI 代理发出的时序信号。
本仓库在这方面的边界同样诚实:invisible_playwright_mcp的系统提示词要求模型"在行动前先检查页面,并偏好一次一个清晰动作而非长链"(见 agent.py 的 SYSTEM_PROMPT),引擎让每次点击的指针走弯曲的人形路径、让键入走真实按键——这些改善的是单个动作的形态。步与步之间的间隙分布仍是模型延迟穿上风衣的样子,无论单个动作多像人,它都可见。
4.1 最廉价的诊断:记录"拦截何时到来"
节奏信号顺带给了你全篇最便宜的诊断:记录拦截发生的时间点。
- 拦截发生在第一次页面加载:指向机器或地址——即上面列出的那些机器级指纹清单;
- 拦截发生在几次交互之后:指向行为或流量,而 代理的重试循环通常是流量那一半。
一个重试和重新规划的循环会把一条指令变成一屏请求:一次失败被回喂给模型、模型重新规划、换选择器、重读页面、重新加载——每一次都是一次新请求。速率限制只计数,它不"看":它从不打开浏览器,只数这个窗口内来自该地址、该账户或该会话的请求数,然后与阈值比较。最逼真的浏览器每请求也只能把计数器加一。
4.2 框架能做的与不能做的
本仓库对自己的循环约束也做了精确说明:没有回合上限(循环一直运行到模型停止调用工具为止,见 agent.py 的 run 循环),单次回复有 8,192 token 上限,指令在单浏览器上串行执行,接口提供一个"运行中变成红色停止按钮"的人工停止开关。诚实地说:人是停止器,不是节流阀。请求的节奏、突发的大小,最终由"你怎么驱动它"决定——失败后不要立即重跑、把大任务拆小、关注出口 IP 而不是浏览器数量、脚本化运行时给它预算和退避。
五、能不能给 browser-use 换上 stealth Firefox?不能
直接说清楚比给你一个不成立的变通方案好。browser-use 通过Chrome DevTools Protocol(CDP)驱动浏览器——配置甚至暴露了cdp_url用于连接一个正在运行的浏览器——而它的executable_path与channel处理只认 Chromium。把 Firefox 二进制塞进executable_path不是即插即用:驱动方会对着一个它不实现的协议说话。
5.1 真正接受不同引擎的路线是 MCP
接受不同引擎的路线是MCP:在那里浏览器是一组工具,而不是一个 CDP 端点。Microsoft 的 Playwright MCP 服务器接受--browser=firefox(原文档作者于 2026-09-03 核对),而 本仓库的 MCP 服务器 走得更远:它内置一个在 C++ 层面打过补丁的 Firefox 作为引擎,指纹设置在引擎自身的源码里,而不是贴在页面上的补丁。一个会说 MCP 的助手——Claude Code、Claude Desktop、Cursor——驱动的是一个指纹来自其自身源码的浏览器。
这正是本仓库invisible_playwright_mcp的形态,几个与浏览器-use 直接对照的事实:
- 仓库在
pyproject.toml中声明支持 Windows 与 Linux(无 macOS),引擎只随这两者发布二进制; uvx invisible-playwright-mcp(无子命令)就是 MCP 服务器本体,python -m invisible_playwright_mcp是接口 spawn 的方式,invisible-playwright-mcp ui是带界面的独立用法(见 README);- 身份由
STEALTHFOX_SEED决定、出口由STEALTHFOX_PROXY决定、登录持久化由STEALTHFOX_PROFILE_DIR决定,三者都是可选环境变量,工具调用可以覆盖它们(见 plan.py 的三值解析逻辑 与 服务器实现); - 默认走 stdio 传输,
STEALTHFOX_MCP_TRANSPORT=http可切换为 streamable HTTP(默认绑定127.0.0.1,端口默认8766)。
5.2 公平地陈述这个权衡
转去 MCP 意味着离开 browser-use 的 agent 循环,改用支持 MCP 的 agent。这个权衡哪边更重,取决于你的拦截来自哪里——用上面"首次加载 vs 交互之后"的测试就能判断:
- 如果拦截是机器形态的(首次加载就被拦),引擎才是关键,而 MCP 是通往不同引擎的门;
- 如果拦截是节奏形态或流量形态的(交互后被拦),换任何引擎都救不了你——在 browser-use 里如此,在任何地方都如此。
六、结论:三堆问题,一个诊断
browser-use 暴露的配置足以修复"配置能修复的两件事":跑哪个浏览器二进制,以及 profile 有没有过去。指向真实 Chrome、用有历史的 profile,你就拿走了全部可得的收益。
其余的一切分成两堆:
- 机器级 tell:与所有自动化工具共享,靠换机器或换引擎解决——两者都不是 browser-use 的设置,而且换引擎的路线走 MCP,不走
executable_path; - agent 节奏与流量 tell:agent 特有,任何指纹工作都修不了。
一个观察——拦截什么时候到来?——就能告诉你自己属于哪一堆。
七、常见问题速答
为什么我的 browser-use 代理在服务器上被拦、本地却没事?因为服务器没有 GPU、字体很少、没有音频设备、屏幕是默认分辨率,而代理在两个地方完全一样。变的是机器,不是代码。
我能在 browser-use 里设置自定义浏览器吗?能:BrowserProfile的executable_path,它期望 Chromium 家族二进制。指向你真实安装的 Chrome 而不是捆绑的 Chromium 是值得做的。
我能在 browser-use 里用 stealth Firefox 吗?不能。它走 CDP 驱动,浏览器处理只认 Chromium。接受不同引擎的路线是 MCP,配合一个不同的 agent。
持久化 profile 有用吗?有用,比大多数设置都有用,因为它是唯一能给浏览器一段"历史"的设置。先读清楚它的陷阱(锁死、身份一致性)再动手。
为什么拦截在几次动作之后才来,而不是立刻?那指向行为或流量而不是指纹:agent 的节奏和它的重试流量都只在它开始行动后才可见。
加代理能解决吗?它只改变你来自哪里,仅此而已。如果浏览器正在通过 GPU、字体和屏幕宣告自己是一台服务器,那地址从来就不是问题所在。
八、仓库证据与延伸阅读
本文涉及的本仓库证据与可继续深入的材料:
- MCP 服务器文档:各客户端的配置块(
mcpServers/context_servers/servers/ TOML)、STEALTHFOX_*环境变量表、全部工具与main/support双浏览器模型; - AI 代理发出的时序信号:节奏信号的完整解剖,以及"变化、且依赖步骤"的停顿建议;
- 代理重试循环与速率限制:流量那一半的信号,含带退避的脚本示例;
- 为什么我的 AI 代理会被拦:四层模型的完整地图与检查顺序;
- browser-use 的替代方案:更广的替代格局与诚实的对比;
- 源码实现:plan.py(seed/profile/proxy/headless 的三值解析)、server.py(stdio 与 HTTP 传输、默认端口 8766)、agent.py(系统提示词、8,192 token 上限、无回合上限的循环);
- README.md:两种使用方式(MCP 接入与独立 UI)、
--proxy/--seed/--profile-dir/--headed/--binary等 CLI 选项,以及.env的优先级(--flag> 环境变量 >.env> 默认值)。
本文源自 browser-use getting blocked 一文,其内容撰写于维护invisible_playwright_mcp的过程中——这个仓库运行在文中描述的补丁级 Firefox 引擎之上。文章明确说明该引擎不适合 browser-use,因为它确实不适合;一份声称可以的技术指南只会浪费你的时间。
- 人工智能
- AI Agent
- 浏览器控制
- GUI 自动化
- MCP 服务
【免费下载链接】invisible_playwright_mcp
Playwright MCP server undetected by anti-bots and captchas: AI agent browses the web on anti-detect stealth Firefox, Python, undetected browser automation, scraping, computer use.
相关推荐
为什么你的广告拦截器总被发现?终极解决方案来了
为什么你的广告拦截器总被发现?终极解决方案来了 Anti Adblock Killer是一款强大的工具,能帮助你在访问要求禁用广告拦截器的网站时,继续保持广告拦
前端网络安全Dozzle Cloud 数据边界指南:什么数据离开你的主机、如何拦截以及云端的存储与删除
Dozzle Cloud 数据边界指南:什么数据离开你的主机、如何拦截以及云端的存储与删除 Dozzle 自托管实例通过 出站连接 与 Dozzle Cloud
可观测性日志分析后端运维jev-ultrafast做不到什么?浏览器Agent的能力边界、已知限制与路线图清单
jev ultrafast做不到什么?浏览器Agent的能力边界、已知限制与路线图清单 jev ultrafast 是目前速度最快、成本最低档的开源浏览器Age
AI Agent浏览器控制人工智能AI 应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考