1. 这个项目到底在解决什么痛点
第一次看到"让 AI 直接用你已经登录好的浏览器"这个描述时,我的反应是:终于有人把这件事做对了。做过 AI Agent 自动化的人都知道,浏览器自动化最烦人的从来不是写代码,而是登录态。你写一个脚本去抓某个后台的数据,代码逻辑十分钟就写完了,结果卡在登录页面上耗了一整天——验证码、短信验证、扫码登录、设备指纹,随便一个都能让脚本原地趴窝。
传统的解法无非几种:要么用 Selenium 或 Playwright 启动一个全新的浏览器实例,然后想办法把 cookie 塞进去;要么用无头浏览器配合账号密码硬登,但很多站点会检测无头特征直接拒绝;要么干脆手动导出 cookie 再注入,但 cookie 有有效期,过期了又得重来。这些方案我都试过,说实话,没有一个省心的。尤其是那些带二次验证的企业系统,你根本没法用脚本完成登录流程。
腾讯开源的 BrowserSkill 这个项目,思路完全不一样。它不去模拟登录,而是直接接管你已经登录好的那个浏览器。你平时用的 Chrome,该登的账号都登着,该有的 cookie 都在,BrowserSkill 通过某种方式让 AI 能够操作这个已经处于登录状态的浏览器实例。这就绕开了整个登录环节——因为登录这件事,你早就用人手完成了。
这个思路的价值在于:它把"人负责登录、AI 负责操作"这个分工明确化了。登录这种需要人机交互、涉及安全验证的环节交给人,而重复性的点击、填表、抓取、导航交给 AI。对于做 RPA、数据采集、自动化测试、AI Agent 开发的人来说,这几乎是把最大的一个障碍给搬走了。
适合读这篇内容的人:正在做浏览器自动化的开发者、想给 AI Agent 加上网页操作能力的产品经理、被登录态问题折磨过的测试工程师,以及所有对"AI 操作浏览器"这个方向感兴趣的技术人。下面我会从原理、部署、实操、踩坑几个维度,把这个项目拆开讲清楚。
2. BrowserSkill 接管已登录浏览器的核心机制
2.1 为什么不能简单地"复制 cookie"
很多人第一反应是:接管已登录浏览器,不就是把 cookie 复制出来吗?我一开始也这么想,但实际做过就知道,这条路走不通,原因有好几层。
第一层是cookie 的绑定问题。现代浏览器的 cookie 往往和设备的指纹、User-Agent、甚至 TLS 指纹绑定。你把 cookie 复制到另一个浏览器实例里,服务端一比对发现指纹对不上,直接判定为异常登录,轻则要求重新验证,重则封号。我踩过这个坑,某次把 cookie 导到脚本里跑,结果账号被风控了三天。
第二层是localStorage 和 IndexedDB。现在很多单页应用(SPA)的登录态根本不在 cookie 里,而是存在 localStorage 或者 IndexedDB 中。你光复制 cookie 没用,token 在 localStorage 里躺着呢。而 localStorage 是按域名隔离的,你没法简单地跨实例搬运。
第三层是会话的动态性。有些系统的 token 是滚动刷新的,你复制出来的那一刻是有效的,但几分钟后就失效了,因为原浏览器已经刷新了 token,而你手里的还是旧的。
BrowserSkill 的做法是不复制,而是连接。它通过 Chrome 的远程调试协议(CDP,Chrome DevTools Protocol)连接到你已经运行的浏览器实例上。CDP 是 Chrome 官方提供的调试接口,你平时按 F12 打开开发者工具,用的就是这个协议。BrowserSkill 相当于在外部扮演了一个"开发者工具"的角色,通过 CDP 向浏览器发送指令:打开这个页面、点击这个按钮、读取这个元素的内容。
2.2 CDP 连接与常规自动化的本质区别
这里要讲清楚一个关键区别,否则后面实操容易懵。
常规的 Playwright/Selenium 自动化,是启动一个新的浏览器进程,然后通过 WebDriver 协议或者 CDP 控制这个新进程。这个新进程是干净的,没有你的登录态,没有你的插件,没有你的书签。
BrowserSkill 走的是连接已有进程的路线。你手动启动 Chrome 的时候加一个--remote-debugging-port参数,Chrome 就会在指定端口上开放 CDP 接口。BrowserSkill 连上这个端口,就能操作这个浏览器里的一切——包括你已经登录的所有账号。
打个比方:常规自动化像是你新买了一台电脑,什么都要重新配置;BrowserSkill 像是你直接坐到自己的电脑前,用你平时用的那个浏览器干活。区别就是这么直接。
注意:用
--remote-debugging-port启动的 Chrome,会使用一个独立的用户数据目录,除非你显式指定。这一点后面部署章节会详细讲,是新手最容易翻车的地方。
2.3 "Skill"这个词背后的设计哲学
项目叫 BrowserSkill,这个"Skill"不是随便起的。它暗示了这个项目的定位:把浏览器操作封装成 AI 可以调用的技能。
在 AI Agent 的语境里,Skill 通常指的是一种结构化的能力描述——告诉模型"你能做这件事,需要这些参数,会返回这个结果"。BrowserSkill 把"打开网页""点击元素""输入文本""提取内容"这些操作封装成标准化的技能接口,AI 模型通过调用这些接口来完成任务。
这个设计的好处是解耦。AI 模型不需要知道 CDP 协议怎么用,不需要关心元素选择器怎么写,它只需要说"我要点击登录按钮",BrowserSkill 负责把这个意图翻译成具体的 CDP 指令。这种分层让整个系统更容易维护和扩展。
从工程角度看,这种设计也方便做权限控制。你可以限制 AI 只能操作某些域名,或者只能执行某些类型的操作,避免它乱点乱删。这在企业场景里很重要——你不会希望 AI 在你登录的银行后台里自由发挥。
3. 从零跑通 BrowserSkill 的完整流程
3.1 环境准备:Chrome 版本与调试端口
先把基础环境搭好。BrowserSkill 依赖 CDP,而 CDP 的接口在不同 Chrome 版本之间有差异,所以版本选择有讲究。
我实测下来,Chrome 109 及以上版本比较稳。为什么特别提 109?因为 109 是最后一个支持 Windows 7 的主流版本,很多企业内网机器还停留在 Win7,这个版本号在热搜里出现频率很高,说明有不少人卡在这个环境上。如果你用的是 Win10/Win11,直接上最新稳定版就行。
启动带调试端口的 Chrome,命令是这样的:
# Windows "C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="C:\chrome-debug-profile" # macOS /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222 --user-data-dir="/tmp/chrome-debug-profile" # Linux google-chrome --remote-debugging-port=9222 --user-data-dir="/tmp/chrome-debug-profile"这里有个关键点:--user-data-dir参数。如果你不指定这个参数,Chrome 会用默认的用户数据目录,但问题是——如果 Chrome 已经在运行(用默认目录),你再启动一个带调试端口的实例,新实例会直接把参数传给已有实例然后退出,调试端口根本没开起来。这是新手最常踩的坑,表现为"我明明加了参数,怎么连不上"。
指定一个独立的--user-data-dir,就能保证启动的是一个全新的、带调试端口的实例。但这个新实例是干净的,没有你的登录态。所以你需要在这个新实例里手动登录一次,之后这个 profile 目录就保留着登录态了,下次启动直接可用。
提示:把
--user-data-dir指向一个固定目录,登录一次之后就别删了。这个目录就是你的"已登录浏览器"的载体。
3.2 验证调试端口是否真的开了
启动之后,别急着写代码,先验证端口通不通。浏览器访问http://localhost:9222/json/version,如果返回一段 JSON,里面有Browser、webSocketDebuggerUrl这些字段,说明 CDP 接口正常。
如果访问不了,按这个顺序排查:
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
| 连接被拒绝 | Chrome 没启动成功 | 检查命令行参数拼写,看是否有报错 |
| 返回空 | 端口被占用 | 换一个端口,比如 9223 |
| 能访问但列表为空 | 没有打开的标签页 | 手动打开一个网页再试 |
| 启动后立刻退出 | 已有实例在用同一 user-data-dir | 换目录或先关掉所有 Chrome |
我遇到过一种情况:命令行启动 Chrome 后,窗口一闪就没了。查了半天发现是--user-data-dir指向的目录被另一个 Chrome 进程占用了。解决办法很简单,任务管理器里把所有 chrome.exe 结束掉,再重新启动。
3.3 安装与初始化 BrowserSkill
环境通了之后,装 BrowserSkill。具体安装方式取决于你用的语言栈,Python 和 Node.js 都有对应的接入方式。核心逻辑是一样的:建立到 CDP 端口的 WebSocket 连接,然后发送指令。
初始化的时候,你需要指定 CDP 的地址,通常是http://localhost:9222。连接建立后,BrowserSkill 会列出当前所有打开的标签页,你可以选择操作哪一个,也可以新建标签页。
这里有个实操心得:先手动打开目标网站并登录好,再让 BrowserSkill 连接。不要指望 BrowserSkill 帮你完成登录,那不是它的强项。它的强项是在已登录状态下做后续操作。把登录这一步留给人,整个流程会顺畅很多。
3.4 第一个可运行的操作示例
假设你要让 AI 打开某个后台页面,读取一个数据表格。流程大致是:
- 手动启动带调试端口的 Chrome,登录目标系统
- BrowserSkill 连接到该 Chrome
- 发送"导航到某 URL"的指令
- 发送"等待某元素出现"的指令
- 发送"提取某元素文本"的指令
- 拿到数据,交给 AI 处理
每一步的指令都是标准化的,AI 模型只需要决定"下一步做什么",具体的 CDP 调用由 BrowserSkill 封装。这就是前面说的"技能化"的价值——把复杂的底层操作变成简单的意图表达。
4. 实际使用中最容易翻车的几个地方
4.1 元素定位的稳定性问题
浏览器自动化最头疼的永远是元素定位。页面上一个按钮,你用 class 定位,结果前端一改版 class 变了,脚本就挂了。用 XPath 定位,嵌套层级一深,稍微动一下就失效。
我的经验是优先用文本内容定位,其次用稳定的属性(如 id、name、data-* 属性),最后才用 class 和 XPath。文本内容虽然也可能变,但相对稳定,而且更符合"人类操作"的直觉。BrowserSkill 这类工具通常支持多种定位策略,选对策略能省很多维护成本。
还有一个技巧:加等待,但不要用固定 sleep。固定 sleep 要么太短导致元素还没出来,要么太长浪费时间。用"等待元素出现"这种条件等待,效率高得多。BrowserSkill 一般会提供这类等待接口。
4.2 多标签页和 iframe 的坑
现代网页大量使用 iframe,而 CDP 操作 iframe 里的元素需要先切换到对应的 frame 上下文。如果你发现"元素明明在页面上,就是定位不到",八成是 iframe 的问题。
多标签页也是类似。BrowserSkill 连接的是整个浏览器,不是单个标签页。你操作之前要明确指定操作哪个标签页,否则可能操作到错误的页面上。我踩过一次坑:脚本在 A 标签页操作,结果因为焦点在 B 标签页,点击事件发到了 B 上,数据全乱了。
提示:每次操作前先确认当前活跃的标签页和 frame 上下文,这是写稳定脚本的基本功。
4.3 登录态过期与风控触发
即使是接管已登录浏览器,登录态也可能过期。尤其是那些有会话超时机制的系统,你放着不管几个小时,token 就失效了。这时候 BrowserSkill 的操作会失败,因为页面跳转到了登录页。
处理方式有两种:一是定期检查当前 URL,如果发现跳到了登录页就暂停任务并通知人工处理;二是设置合理的任务间隔,别让会话闲置太久。
风控是另一个隐患。虽然你用的是真实浏览器、真实登录态,但如果操作频率过高、行为模式太机械,依然可能触发风控。我的建议是给操作加上随机延迟,模拟人类的操作节奏。点击之间隔个几百毫秒到一两秒,不要像机器一样精确到毫秒。
4.4 调试端口的安全边界
--remote-debugging-port打开的端口,任何能访问这个端口的程序都能控制你的浏览器。这意味着如果你把端口暴露在公网上,等于把浏览器控制权交出去了。
所以调试端口只监听 localhost,不要绑定到 0.0.0.0。默认情况下 Chrome 的调试端口就是只监听本地的,但如果你在容器或远程环境里跑,要注意网络配置,别不小心暴露了。用完记得关掉带调试端口的 Chrome 实例。
5. 把 BrowserSkill 接入 AI Agent 的几种思路
5.1 工具调用模式:让模型决定下一步
最直接的接入方式是工具调用(Tool Calling)。把 BrowserSkill 的每个操作封装成一个工具,比如open_url、click_element、extract_text,然后把工具列表告诉 AI 模型。模型根据当前任务和页面状态,决定调用哪个工具、传什么参数。
这种模式适合目标明确但路径不确定的任务。比如"帮我在这个后台找到上个月的销售报表并下载",具体点哪个菜单、进哪个页面,模型可以自己探索。你只需要提供工具,不需要写死流程。
实现上的关键是给模型足够的页面状态信息。模型看不到页面,它只能通过你提供的文本描述来理解当前状态。所以每次操作后,要把页面的关键信息(标题、可见文本、可交互元素列表)反馈给模型,它才能做出下一步决策。
5.2 固定流程模式:把确定性交给代码
如果任务流程是固定的,比如"每天登录后台导出数据",那就没必要让模型去探索。直接用代码写死流程,BrowserSkill 只负责执行。模型在这里的作用是处理异常——比如某个元素没找到,让模型看看页面截图,判断是页面改版了还是加载慢了。
这种模式更稳定、更可控,适合生产环境。我的建议是:能用固定流程解决的,就别上模型。模型的不确定性在自动化场景里往往是负担,不是优势。
5.3 混合模式:固定骨架 + 模型兜底
实际项目里我用得最多的是混合模式。主流程用代码写死,保证稳定性;在几个容易出问题的环节(比如元素定位、页面判断)留出模型介入的接口,出问题时让模型来决策。
举个例子:脚本要点击"导出"按钮,正常情况用选择器直接点。如果选择器失效了,就把页面截图发给模型,让模型告诉你"导出按钮在页面右上角,文字是'导出报表'"。然后脚本根据模型的描述重新定位。这样既保证了正常情况下的效率,又有了异常情况下的鲁棒性。
5.4 和 Vue 项目里的地图类组件配合的场景
热搜里出现了"用在 vue 里的腾讯地图"这类词,说明有不少人在做前端项目时遇到类似需求。如果你的 Vue 项目里嵌了地图组件,想让 AI 操作地图(比如搜索地点、切换图层),BrowserSkill 同样适用。地图组件本质也是 DOM 元素加 Canvas 渲染,DOM 部分可以直接操作,Canvas 部分可能需要模拟鼠标事件。
这类场景的难点在于地图的交互是连续的——拖拽、缩放这些操作不是单次点击能完成的。你需要模拟鼠标按下、移动、抬起的完整序列。BrowserSkill 如果支持底层鼠标事件,就能处理这类需求。
6. 这套方案适合和不适合的场景
6.1 强烈推荐的场景
企业内部系统的自动化。这类系统通常登录复杂(可能有二次验证),但登录后操作相对固定。用 BrowserSkill 接管已登录浏览器,能省掉最麻烦的登录环节。我见过一个财务对账的场景,人工每天要花两小时在三个系统之间倒数据,用这套方案后压缩到十分钟。
需要保持登录态的长期任务。比如监控某个后台的数据变化,或者定时抓取需要登录才能看的内容。传统方案要反复处理登录,BrowserSkill 一次登录长期使用。
AI Agent 的网页操作能力补充。如果你在做一个能帮用户处理网页任务的 Agent,BrowserSkill 提供了一套现成的浏览器操作接口,不用自己从零封装 CDP。
6.2 需要谨慎的场景
高并发的采集任务。BrowserSkill 连接的是单个浏览器实例,并发能力有限。如果你要同时操作几十个页面,这套方案不合适,还是得用无头浏览器集群。
对稳定性要求极高的生产系统。接管已登录浏览器意味着依赖人工登录这一步,如果登录态失效而没人处理,任务就断了。关键业务要有监控和告警机制。
涉及敏感操作的场景。让 AI 操作你登录的银行、支付类系统,风险很高。即使有权限控制,也建议加人工确认环节,别让 AI 全自动执行。
6.3 和其他方案的对比
| 方案 | 登录态处理 | 稳定性 | 并发能力 | 适用场景 |
|---|---|---|---|---|
| BrowserSkill 接管已登录浏览器 | 人工登录,天然保持 | 中高 | 低 | 内部系统、长期任务 |
| Playwright 启动新实例 | 脚本模拟登录 | 中 | 高 | 公开网站、测试 |
| 无头浏览器 + cookie 注入 | 手动维护 cookie | 低 | 高 | 简单采集 |
| 纯 API 调用 | 无需浏览器 | 高 | 高 | 有开放接口的系统 |
这张表的核心结论是:没有银弹,选方案要看场景。BrowserSkill 的独特价值在于"已登录"这三个字,凡是登录态是核心痛点的场景,它就值得考虑。
7. 一些实操中攒下来的经验
先说一个反直觉的结论:别追求全自动。我早期做自动化总想着一步到位,从登录到操作全让脚本干。结果就是登录环节三天两头出问题,整个流程跟着崩。后来改成"人工登录 + 自动操作",稳定性直接上了一个台阶。BrowserSkill 的设计哲学其实就是在鼓励这种分工,顺着它的思路走,别跟它较劲。
第二个经验是给 AI 的操作加上"确认"环节。尤其是涉及提交、删除、支付这类不可逆操作时,让 AI 先描述它打算做什么,人工确认后再执行。这不是不信任 AI,而是工程上的风险控制。我在一个项目里加了这个环节,成功拦下过一次 AI 误点"批量删除"的事故。
第三个经验关于日志。BrowserSkill 的每次操作都要记日志:什么时间、操作了哪个页面、点了什么元素、结果如何。出问题时这些日志是唯一的线索。我习惯把页面截图也存下来,配合日志一起看,排查效率高很多。
第四个经验是版本锁定。Chrome 自动更新有时候会改变 CDP 的行为,导致原本正常的脚本突然失效。生产环境里我会锁定 Chrome 版本,更新前先在测试环境验证。这个习惯帮我避免了好几次半夜被叫起来处理故障。
最后说一个关于用户数据目录管理的小技巧。给每个自动化任务分配独立的--user-data-dir,任务之间互不干扰。目录命名带上任务标识和日期,方便清理。定期备份重要的 profile 目录,万一登录态丢了还能恢复。这些细节看起来琐碎,但真正跑起来之后,它们决定了你的方案是能长期稳定运行,还是三天两头需要人工救火。