先说个最近的场景。有个朋友给我抛了个活:后台系统里几百条商品信息要批量录入,页面是传统表格,没 API 可调,唯一的办法就是人工一条条填。他问能不能写个脚本,我说脚本倒是不难,难在登录——脚本启动的是一个全新浏览器,没有登录态,还得扫码、收验证码。后来我研究了一圈,发现腾讯开源了一个项目,思路相当直接:与其让 AI 去"重新造一个浏览器"来干活,不如直接接管你已经打开、已经登录好的那个浏览器。这篇文章我就围绕这个项目,从原理到实操拆开讲,适合自己写 Agent、做自动化测试、搞 RPA 和网页数据采集的同学参考。
先说清楚它能解决什么问题。传统的 Selenium、Playwright 脚本每次跑起来都是一个干净浏览器,Cookie 是空的、登录态不存在,遇到企业微信扫码、短信验证码、二次验证这些环节基本直接卡死。而这个腾讯开源项目(下面我统一叫它"这个项目")的核心卖点就是:复用你现有浏览器的登录会话,让 AI 像真人一样,在你已经登录的页面里执行点击、输入、跳转、抓取。
这篇文章不吹不黑,我会把背后的 CDP 协议、大模型页面理解方式、登录态复用原理讲明白,再给出一个能跑通的最小 Demo,最后把我在实操里踩过的坑全部列出来。废话不多说,直接开始。
1. 这个开源项目,解决的是 AI 操作网页的"登录地狱"
1.1 传统浏览器自动化的死穴:一切从登录开始
如果你写过网页自动化脚本,一定对下面的流程不陌生:启动一个无头浏览器 -> 打开登录页 -> 输入账号密码 -> 等待人工扫码 -> 超时 -> 重试。这个过程不仅慢,而且极其脆弱。
问题出在哪?本质上,浏览器的登录态是跟"浏览器用户数据目录"绑定在一起的,包括 Cookie、LocalStorage、IndexedDB,甚至还有指纹信息。正常你用 Chrome 登录过某个系统后,下次打开浏览器,登录态还在,你什么都不用做。但自动化工具为了追求"干净环境",默认每次都初始化一个全新的浏览器实例,相当于把你常用的那个"带记忆的浏览器"扔掉了,换了个失忆的。
更多时候,账号还有风控策略。一个全新的无头浏览器突然访问你的内网后台,设备指纹完全不同,IP 也变了,系统大概率判定为异常登录。轻则让你收验证码,重则直接封号。
所以很多自动化项目在真实的业务场景里跑不起来,不是因为操作逻辑写不出来,而是永远过不了登录这道门槛。这个项目的切入点非常聪明:我不帮你解决登录,我直接躲过登录——既然你电脑上已经有一个登录好的 Chrome,AI 直接去用它不就行了?
1.2 核心思路:接管正在使用的浏览器,而不是重新造一个
传统方案和这个项目有个本质区别,我做了一张对比表:
| 维度 | 传统自动化(Selenium 启新实例) | 本项目(接管已登录浏览器) |
|---|---|---|
| 登录态 | 无,需重新登录 | 继承现有 Chrome 的全部会话 |
| 验证码/扫码 | 频繁触发,无法绕过 | 基本不会触发,因为就是日常环境 |
| 页面渲染 | 无头模式,部分网站不兼容 | 有头模式,和真人使用一致 |
| 指纹一致性 | 全新指纹,易被风控 | 与日常一致,风控难度低 |
| 环境依赖 | 需要独立的 driver 和浏览器 | 只要能连上 CDP 端口即可 |
一句话概括:传统方案是"替用户开个新浏览器",这个项目是"接管用户已开着的浏览器"。
顺带说一句,市面上 Browser-Use 这类开源方案也很火,但大多是自带一个 Playwright 启动的浏览器实例。腾讯开源的这个项目,核心卖点就是把"接管已有浏览器"这件事做成了开箱即用,你不需要自己管理用户数据目录、不需要处理登录态迁移,直接对着正在使用的浏览器干活。这种思路在跑企业内部系统、Admin 后台这类强登录场景时,体验是碾压级的。
1.3 谁适合用它:Agent 开发者、测试工程师、RPA 场景
我试用下来的感受是,这项目主要适合三类人。
第一类是在搞 AI Agent 的开发者。你可能已经在用大模型能力写代码、查资料,但想让 Agent 真正去操作某个网站,比如自动发帖、自动填报表、自动巡检,这个项目就是现成的"手"。Agent 负责思考和决策,浏览器负责执行,登录态问题交给这个项目解决。
第二类是自动化测试工程师。以前 UI 自动化测试最头疼的就是登录前置条件,每个用例都要处理一遍登录,现在可以直接基于已登录的浏览器状态开始跑,测试耗时能压缩一大截。
第三类是做 RPA 和内部效率工具的人。公司内部系统普遍没有开放 API,做数据录入、数据同步只能靠页面操作。这类系统又几乎都需要验证身份,用这个项目去接管一个已经由管理员登录好的浏览器,能省掉大量重复劳动。
2. 原理拆解:AI 凭什么能够操作已经登录的浏览器
2.1 CDP 是底层基础:浏览器自动化界的"心电监护"
要理解项目原理,必须先懂一个东西:Chrome DevTools Protocol(CDP,Chrome 开发者工具协议)。
Chrome 浏览器在启动时加一个参数就可以开放一个调试端口。我们平时按 F12 打开的开发者工具,本质上就是通过这个协议和浏览器通信的。它远比 Selenium 这种基于 WebDriver 的方案能力更强,能直接让外部程序读页面 DOM、触发事件、执行 JavaScript、捕获网络请求、截图、模拟真实键盘鼠标,还能访问浏览器底层的 target 和 context。
把 CDP 理解成医院的"心电监护仪"就行:病人(浏览器)身上贴了电极片(调试端口),监护仪(外部程序)通过信号实时查看病人身体状态,还能发出电击指令(执行操作)。只要浏览器活着,监护仪就能和它实时对话。
这里最关键的点在于:CDP 连接的是一个已经运行着的浏览器进程。也就是说,浏览器里已有的所有状态——Cookie、登录态、打开着的标签页、已填写的表单——全部对外部程序可见、可用。这个项目借助 CDP,让 AI 拿到的不只是"一个浏览器",而是一个"带着你全部身份的浏览器"。
2.2 大模型怎么"看懂"页面:三种主流技术路线对比
连接上浏览器只是第一步,AI 还需要理解"页面上有什么、应该点什么"。大模型操作网页的技术路线,目前主流的有三种。我把它们的优劣列出来:
| 技术路线 | 原理 | 优点 | 缺点 | token 消耗 |
|---|---|---|---|---|
| DOM/A11y 树 + 文本模型 | 把页面 DOM 转成文本或 accessibility tree,交给大模型理解 | 精准,能定位元素 ID/选择器 | DOM 很大时 token 爆炸 | 中等偏高 |
| 截图 + 视觉模型 | 直接把页面截图丢给多模态大模型,让它输出点击坐标或动作描述 | 直观,不依赖 DOM 结构 | 对小图标、密集表格识别不稳 | 较低 |
| 混合方案 | 先用 DOM 找候选元素,再截图确认后操作 | 最接近真人行为,成功率最高 | 工程复杂度高 | 中等 |
腾讯开源的这个项目,实际走的是混合方案。它默认把页面的可交互元素提取出来(链接、按钮、输入框、下拉选项),再配合页面截图,让大模型基于"文字候选 + 视觉信息"共同决策。这样避免了纯文本方案 token 爆炸的问题,也缓解了纯视觉方案定位不准的问题。
我想起一句话:AI 操作浏览器,难的不是"会点",而是"知道点什么"。混合方案本质上是给了 AI 两条感知通道:一条看结构,一条看长相,双管齐下,决策可靠性明显高于单通道。
2.3 核心循环与成本估算
AI 操作网页并不是一锤子买卖,它和真人的行为模式一样,是一个循环:
感知(截图/提取 DOM)-> 决策(大模型决定下一步操作)-> 执行(点击/输入/滚动)-> 观察结果(页面变化)-> 再决策……
每个动作背后都至少调用一次大模型接口,所以成本是必须算清楚的。根据我在类似项目上的实测经验,一个简单的操作任务(比如把某个表单填完提交),平均要走 6-12 步。以现在主流的性价比型多模态模型来算,每步约消耗 2000-4000 token(截图约 1000 token,响应约 1500 token),单次任务合计大概 2-4 万 token。
按市面常见定价粗算,一步几厘钱,一个完整任务一两毛人民币。说实话,这个成本在真实业务里完全可以接受,毕竟省下的是一个人半小时的重复劳动。真正要警惕的不是单次成本,而是任务失控导致无限循环,一个 bug 让 Agent 原地打转,调个几十步,那成本就不是按任务算而是按小时烧了。这个我在第 4 章专门讲怎么防。
3. 实操:让 AI 接管你的 Chrome 并完成真实任务
3.1 第一步:启动带调试端口的浏览器实例(含参数说明)
先说明一点,这个项目支持直接连接已经在运行的浏览器,但需要该浏览器以调试模式启动。如果你希望 AI 操作的是日常正在用的 Chrome,最简单的做法是完全退出 Chrome,然后通过调试参数重新启动它。
以 Windows 为例,命令行这样写:
"C:\Program Files\Google\Chrome\Application\chrome.exe" --remote-debugging-port=9222 --user-data-dir="D:\ChromeDebugProfile"这里有两个关键参数,分开解释。
--remote-debugging-port=9222:让 Chrome 开放 9222 端口,CDP 协议对外可访问。--user-data-dir="D:\ChromeDebugProfile":指定一个独立的用户数据目录。这个目录用来存放 Cookie、登录态、扩展等,相当于让这个实例"记住"它自己干过什么。
如果你想直接复用当前正在用着的 Chrome 登录态,更推荐的玩法是:保持现有 Chrome 不动,另开一个调试实例,但这个实例指向你常用 Chrome 的同一份用户目录。这样 AI 操作的浏览器登录态和你的日常登录态是一致的,又不会影响你正在开着的窗口。
注意:如果你日常 Chrome 正在运行,直接敲命令行加
--remote-debugging-port=9222通常不会生效,因为 Chrome 发现已有进程后会把参数转交给老进程,而老进程没带调试端口。最稳妥的办法就是先退出所有 Chrome 进程,或者使用独立的--user-data-dir启动一个全新实例。
启动成功后,浏览器会开一个空白窗口。你在浏览器地址栏访问http://127.0.0.1:9222/json,如果能看到一堆 JSON 数据,里面有页面标题和webSocketDebuggerUrl,就说明调试端口已经通了。
3.2 第二步:用代码连接已有浏览器,验证登录态
现在打开你熟悉的代码编辑器,安装连接库。我自己更推荐 Playwright,因为它的connect_over_cdp接口就是为这种场景设计的,比直接裸写 WebSocket 省事很多。
pip install playwright然后写一段连接代码:
import asyncio from playwright.async_api import async_playwright async def main(): async with async_playwright() as p: # 通过 CDP 连接已经启动的 Chrome browser = await p.chromium.connect_over_cdp("http://127.0.0.1:9222") context = browser.contexts[0] page = context.pages[0] # 访问一个需要登录的网站,验证登录态是否还在 await page.goto("https://github.com") title = await page.title() print("当前页面标题:", title) # 检查本地存储 / Cookie 是否存在,判断登录态 cookies = await context.cookies() print("Cookie 数量:", len(cookies)) asyncio.run(main())如果你在这个浏览器里已经登录过 GitHub,运行这段代码后会直接看到你的个人主页相关页面,而不是登录页。你可以顺手截个图确认:
await page.screenshot(path="snapshot.png")看这张截图里是不是你熟悉的登录后界面,是就说明 AI 已经继承了你的登录身份。
这里插一个我实际踩过的坑:browser.contexts[0]不一定是你看到的那个有登录态的页面上下文。Chrome 中普通标签页上下文通常排在第 0 位,但如果你开了隐身窗口或者装了特殊扩展,顺序可能变化。稳妥的做法是遍历browser.contexts,对每个 context 遍历pages,找到标题或 URL 符合预期的那个 page 再操作。
3.3 第三步:接入大模型,跑通"感知-决策-执行"闭环
连接上浏览器只是拿到了"手",AI 还需要"脑子"。这个项目的价值就在于把大脑和手接在了一起,但我们自己写一个最小闭环也不难,核心代码如下:
from playwright.async_api import async_playwright import asyncio MAX_STEPS = 10 async def llm_decide(page, task, step): """调用多模态大模型,决定下一步动作。 返回:{"type": "click"/"fill"/"finish"/"scroll", ...} 这里省略具体调用代码,你可以接任何一个视觉模型。 """ screenshot = await page.screenshot() # 把截图 + 任务描述 + step 发给大模型,让它返回动作 JSON ... async def run_agent(task: str): async with async_playwright() as p: browser = await p.chromium.connect_over_cdp("http://127.0.0.1:9222") context = browser.contexts[0] page = context.pages[0] for step in range(MAX_STEPS): action = await llm_decide(page, task, step) if action["type"] == "click": await page.click(action["selector"], timeout=5000) elif action["type"] == "fill": await page.fill(action["selector"], action["value"]) elif action["type"] == "scroll": await page.mouse.wheel(0, action["delta_y"]) elif action["type"] == "finish": print("任务完成") break await asyncio.sleep(0.5) # 等页面稳定 asyncio.run(run_agent("在 GitHub 上把这个仓库的 Star 加一"))我强烈建议你在llm_decide里把页面上的可交互元素信息一起传给模型,比如按钮的文字和它的 XPath。混合信息能让模型决策准确率高很多。如果你只发截图,模型经常会给你一个不太准的坐标;如果你只发 DOM 文本,遇到动态渲染的表单又容易漏掉元素。两者结合才是成品级方案。
视觉模型的选型,腾讯家自己的混元视觉模型、开源的 Qwen-VL、GLM-4V,以及闭源 GPT-4 系列,都能干这个活。输出格式建议强制约束为 JSON,用response_format之类的参数或提示词严格限定,不然模型自由发挥出natural language回复,根本没法解析执行。
3.4 安全边界:给 AI 浏览器权限之前想清楚
这里必须泼一盆冷水。让 AI 接管你的浏览器,等于把你所有账号的"钥匙"都交给了 AI。它不仅能填表、点击,理论上也能读取你 Gmail 里的邮件、访问你微信网页版的聊天记录、在你淘宝里下单。
我在实际使用中的几个安全守则:
- 专用用户目录:不要直接用你日常上班用的 Chrome 主用户目录,建议新建一个独立的
--user-data-dir,在里面单独登录一次需要的系统,然后再让 AI 接管。这样即使 Agent 失控,影响范围限定在专用目录内。 - 只授权具体任务:给 Agent 限定的目标,比如"在后台系统把 Excel 里的商品录入进去",不要给过于开放的任务描述。
- 加权限管控:如果你的浏览器有多个 Profile,把含有重要个人账号的 Profile 隐藏起来或直接不用那个实例。
- 审计日志:在 Agent 执行循环里记录每一步的操作截图、选择器、动作类型,出问题时能快速回溯。
说实话,这个项目的设计和初衷是好的,但能力越强的工具越需要约束。体验"让 AI 帮你做事"的爽快感之前,先做好隔离和审计。这条建议价值千金。
4. 常见问题排查与避坑实录
4.1 调试端口连不上的 5 个原因
我在折腾 CDP 连接时,头一天基本全在排查连接问题。下面这张表是高频问题的排查清单:
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
http://127.0.0.1:9222/json无法访问 | Chrome 没带调试端口启动 | 退出 Chrome 后用--remote-debugging-port=9222重新启动 |
| 端口被占用 | 其他程序占了 9222 | 换端口如 9223,记得代码里同步改 |
| 连接后 context 为空 | Chrome 没有打开任何页面 | 手动打开一个页面再连 |
| 页面列表里看不到目标页面 | 目标页面在隐身窗口或另一个 context | 遍历全部 contexts 查找 |
| 连上但执行报错 | Chrome 版本过旧,CDP 接口不兼容 | 升级 Chrome/Edge 到最新版 |
最经典的坑是我上面提过的:Chrome 已经在运行,你执行命令行带了调试参数,Chrome 检测到已有进程就直接把参数丢弃了。结果是浏览器打开了但是 9222 端口根本没监听。想连调试端口,必须先保证目标浏览器进程是"全新启动并且带调试参数"的。
4.2 登录态相关问题的处理
既然这个项目的核心卖点是复用登录态,那登录态失效就是最让人头疼的问题。常见场景和排查思路:
第一,无头模式丢登录态。有些版本的 Chrome 在 headless 模式使用不同的加密存储方式,Cookie 可能读不出来,网站也容易识别出无头环境。我的建议是别用无头模式,直接有头跑。自动化任务跑在服务器上也可以装一个虚拟桌面,或者用Xvfb这类工具模拟显示器,保证浏览器以完整状态运行。
第二,用户目录不一致。这个问题特别隐蔽,你以为两个 Chrome 用的是同一份数据,但实际上因为命令行参数路径写错、权限不同、盘符不同,导致浏览器另建了一份用户目录,所有 Cookie 全部丢失。排查方法很简单:在浏览器地址栏访问chrome://version,看 "个人资料路径" 是否指向你预期的那条路径。
第三,风控仍然存在。即使登录态复用了,如果浏览器长期不操作后突然高频点击、快速输入,或者访问频率远超人类极限,账号仍然可能被风控。我的经验是给 Agent 的每个动作之间加随机延迟(不是固定延迟,是人眼扫视所需的 200-500ms 随机间隔),并且单次任务的页面操作总数控制在合理范围内。
这里多说一句,网站的安全机制越来越严格,有些站点会检测 CDP 调试特征。如果你的目标站点恰好有这种检测,这个方案可能会失效。这种情况下没有什么一劳永逸的解法,要么降低操作频率,要么考虑走官方 API,不建议和对方的检测机制硬碰硬。
4.3 Agent 任务执行中的失控场景
Agent 不像传统脚本是严格线性执行,它是"边看边做",所以天然存在失控风险。
最常见的是死循环。比如页面加载慢,Agent 截图看到的还是旧状态,于是反复点击同一个按钮。我加了MAX_STEPS上限之后,至少把损失控制住了,但这只是治标。治本的办法是引入"状态指纹":每次循环前把页面的关键文本哈希一下,如果连续 3 步哈希相同,强制切换策略或者中断。
其次是误点击风险。模型给的 selector 可能命中多个元素,或者页面动态渲染后选择器失效。我建议点击前先判断元素是否可见、是否在视口内,必要时滚动到目标位置再点。
还有验证码陷阱。有的网站在多次交互后会弹出滑块验证码,视觉模型能识别但执行时容易滑过头。我目前的处理方式有两种:一是暂停任务,把截图推给人做确认;二是重点检查验证码出现的时机,尽量在触发之前完成必要操作,减少交互次数。
4.4 部署模式与多账号隔离方案
如果你真要把这类 Agent 用于生产环境,我推荐按下面几种部署模式来规划:
| 模式 | 场景 | 优点 | 缺点 |
|---|---|---|---|
| 连接本机日常 Chrome | 临时调试、验证想法 | 最方便,登录态最全 | 有账号风险,不适合长时间任务 |
| 专用调试实例(固定 user-data-dir) | 单账号自动化任务 | 登录态可复用,隔离性好 | 需要单独启动、维护 |
| 多端口多目录沙箱 | 多个账号并发 | 账号互不干扰,支持并行 | 资源占用高,要管理端口池 |
我自己生产环境用的是第三种思路:写一个启动脚本,每个浏览器实例分配一个独立端口(9222、9223、9224……)和一个独立用户目录,登录态各自维护,任务队列按实例分发。跑起来之后效果不比商业 RPA 差,而且完全可控。
这个模式还有一个额外收益,就是便于测试回滚。每个用户目录就是一个沙箱,任务出了大问题直接把目录删掉重新初始化,比在同一个浏览器里反复试错干净得多。当然代价是磁盘占用变大,一个完整的 Chromium 用户目录大概 200-500MB,需要注意清理策略。
最后分享一点我个人的体会。刚开始玩这个项目时,我也图省事直接让它接管我到处登录过的日常浏览器,确实爽,什么网站都能操作,没有登录阻碍。但有一次 Agent 在理解任务时出了问题,差点在我的个人后台里执行了错误操作,从那次以后我就老实了。现在我所有的 Agent 任务都跑在独立调试实例里,登录态用专用目录维护,需要哪个站点就登录哪个站点,绝不开放全部账号。建议你也尽早养成这个习惯,而不是等翻车了再后悔。