1. 项目概述当AI成为你的浏览器副驾驶如果你和我一样每天有大量时间泡在浏览器里——查资料、填表单、操作各种SaaS后台那你肯定也幻想过要是能有个助手帮我点点按钮、填填表格、上传个文件该多省事。市面上确实有不少AI联网工具但它们大多只能“读”网页抓取文本摘要给你看。一旦需要“动手”操作——比如在飞书文档里编辑、在Jira里创建工单、在内部系统上传附件——这些工具就集体哑火了。更头疼的是你没法让AI直接用你正在用的浏览器。你已经在Chrome里登录了公司内网、企业微信、Notion积累了宝贵的登录态Session。但现有的自动化方案比如Playwright或Puppeteer都得新开一个“干净”的浏览器实例你的登录态带不过去得重新登录一遍麻烦不说有些二次验证还过不了。另一种思路用Chrome DevTools ProtocolCDP直接连你的Chrome虽然能共享登录态但你和AI无法同时操作它一动鼠标你的页面就跟着跳根本没法并行工作。Browser Control Skill这个项目就是为了解决这个核心痛点让人和AI能和平、高效地共用一个真实的浏览器环境。它不是另一个网页爬虫而是一个完整的浏览器操控技能包让AI能真正成为你在浏览器里的“手”帮你完成那些重复、繁琐的交互操作而你可以在一旁监督或者完全放手让它去后台并行处理多个任务。2. 核心设计思路前台协作与后台并行的双模式架构这个项目的聪明之处在于它没有发明一种新的浏览器控制协议而是巧妙地组合利用了现有操作系统的UI自动化能力和浏览器的底层调试协议根据不同的任务场景智能切换两种工作模式。2.1 前台协作模式基于AppleScript的“所见即所得”操作当你正盯着某个页面需要AI即时协助时就适合用前台模式。例如你打开了一个复杂的报销表单想让AI帮你填写。在这个模式下Skill通过AppleScript在macOS上来操控浏览器。为什么是AppleScript因为它能直接与最前端的应用程序窗口对话实现“所见即所得”。当你执行/browse here 点击提交按钮时Skill的底层逻辑是这样的通过AppleScript获取当前最前端的窗口信息确认是Chrome。向Chrome发送JavaScript指令例如document.querySelector(‘button[type“submit”]’).click()。这个点击动作会真实地发生在你眼前的页面上你能看到按钮被按下、表单提交的整个过程。注意这种模式高度依赖UI层的稳定性。如果页面结构在AI操作期间突然变化比如弹出一个加载动画原先定位的元素可能失效导致操作失败。因此它最适合相对静态或你实时监控的页面。2.2 后台并行模式基于CDP的“隐身”多任务处理当你想让AI在后台默默调研不干扰你当前工作时后台模式就派上用场了。比如你需要同时查询5家竞品公司的官网信息。这时Skill会切换到Chrome DevTools Protocol模式。CDP模式是如何做到“隐身”的关键在于targetId。Chrome为每一个标签页Tab、每一个扩展程序页面甚至每一个DevTools窗口都分配了唯一的targetId。后台模式的工作流程是通过CDP命令Target.createTarget创建一个新的、隐藏的浏览器标签页或直接使用一个后台标签页。获取这个新标签页的targetId。所有后续操作导航、点击、截图都通过CDP协议精确发送到这个targetId对应的标签页。你的主窗口、你正在浏览的标签页完全不受影响因为CDP指令没有发送给它们。这种基于协议的直接通信跳过了图形界面效率极高也使得真正的并行操作成为可能。主Agent可以派生出多个子Agent每个子Agent获得一个独立的targetId操作自己专属的标签页同时进行网页调研、数据提取等任务。2.3 智能路由五级通道与自动模式选择不是所有任务都需要动用“浏览器”这个重型武器。Skill内置了一个智能调度层我称之为“五级通道”。它会根据你的指令意图自动选择最经济、最合适的工具链优先级从高到低WebSearch如果只是简单的知识问答如“特斯拉CEO是谁”直接调用搜索引擎API返回摘要最快最省。WebFetch / Jina Reader如果需要获取某个公开网页的文本内容使用无头HTTP请求或专门的转码服务如Jina AI的jina.ai将HTML转为干净的Markdown避免启动浏览器。cURL / 原始HTTP对于极其简单的页面或API接口直接用最基础的HTTP客户端获取原始HTML。CDP 只读模式当页面需要JavaScript渲染如React单页应用但又只需读取内容时会启动一个轻量的CDP连接执行脚本获取DOM状态但不进行任何交互。CDP 完全控制模式只有在前四级都无法满足时——即需要登录态、需要点击、填写、上传等交互操作时——才会启动完整的浏览器控制。当你使用简单的/browse命令时Skill会解析你的指令自动判断该走哪条通道是用前台模式还是后台模式。这种设计极大地提升了响应速度和资源利用效率。3. 关键技术细节与实操要点要让AI稳定、安全地操控浏览器远不止发送点击指令那么简单。下面我拆解几个最关键的技术实现和实操中会遇到的问题。3.1 元素定位与现代前端框架共舞现代网页大量使用React、Vue、Svelte等框架DOM元素动态生成传统的基于固定选择器如#submit-btn的定位方法非常脆弱。Skill在这方面做了大量适配。核心策略混合定位与等待策略语义化属性优先首先尝试通过[data-testid]、[aria-label]、role等测试或无障碍属性定位。这些属性通常更稳定。文本内容匹配对于按钮、链接使用XPath的text()函数或CSS的:contains伪类通过JavaScript实现进行文本匹配。例如找“提交”按钮。视觉与坐标辅助在复杂场景下会结合元素的屏幕坐标和视觉特征通过截图分析进行辅助定位。显式等待在执行任何操作前会注入等待逻辑确保目标元素已经稳定地存在于DOM中并且处于可交互状态如element.isConnected element.offsetParent。一个实际的代码片段示例CDP Helper中async def wait_and_click(self, selector, max_wait10): 等待元素出现并点击 start_time time.time() while time.time() - start_time max_wait: try: # 通过CDP执行JavaScript来查找和等待元素 result await self.client.send(Runtime.evaluate, { expression: f (function() {{ const el document.querySelector({json.dumps(selector)}); if (el el.offsetParent) {{ el.click(); return true; }} return false; }})() , awaitPromise: True }) if result.get(result, {}).get(value): return True except Exception: pass await asyncio.sleep(0.5) raise ElementNotFoundError(fElement {selector} not clickable after {max_wait}s)3.2 文件上传绕过系统对话框的魔法网页文件上传input type“file”通常会触发操作系统的文件选择对话框这是自动化的一大障碍。Skill通过CDP的Page.setFileInputFiles命令完美解决了这个问题。操作原理首先定位到文件输入框元素。通过CDP协议直接将该元素的内部文件列表设置为指定的本地文件路径。浏览器会认为用户已经通过对话框选择了文件从而触发onChange等事件。关键实现async def upload_file(self, input_selector, file_path): 直接向文件输入框设置文件路径 # 1. 先定位到元素获取其backendNodeId node_info await self.client.send(DOM.describeNode, { selector: input_selector }) backend_node_id node_info[node][backendNodeId] # 2. 使用setFileInputFiles命令 await self.client.send(DOM.setFileInputFiles, { files: [os.path.abspath(file_path)], # 必须传绝对路径 backendNodeId: backend_node_id })实操心得这里必须传入文件的绝对路径。相对路径或~/开头的路径浏览器无法识别。在实际集成时需要先对用户传入的路径进行解析和标准化。3.3 富文本编辑器操作征服contenteditableNotion、语雀、Gmail的编辑器都不是普通的textarea而是contenteditable的div。向里面输入文字需要模拟完整的光标定位、选区设置和输入事件。策略Skill放弃了模拟键盘事件容易出错直接使用CDP的Input.insertText命令。async def insert_text_to_editor(self, editor_selector, text): 向富文本编辑器插入文字 # 1. 聚焦到编辑器 await self.client.send(Runtime.evaluate, { expression: fdocument.querySelector({json.dumps(editor_selector)}).focus() }) # 2. 直接插入文本CDP底层会处理光标和选区 await self.client.send(Input.insertText, { text: text })这种方法稳定可靠因为它绕过了浏览器的事件系统直接修改了编辑器的内容状态。3.4 状态同步与错误恢复浏览器自动化最怕的就是状态不同步。比如AI点击了一个按钮以为页面跳转了但实际因为网络延迟没跳后续操作就会全部失败。Skill的应对机制操作后状态验证每个重要操作如点击导航、提交表单后都会等待并检查页面状态是否如预期变化如URL改变、特定元素出现。心跳与超时长时间任务会定期通过CDP发送Runtime.evaluate执行简单脚本如11来检测连接和页面是否存活。异常捕获与重试定义了分级错误网络超时、元素未找到、脚本执行错误并针对可重试错误如元素未找到设计了指数退避的重试逻辑。上下文快照在关键步骤前会通过截图和关键DOM序列化保存页面快照。如果后续步骤失败可以尝试恢复到上一个已知状态点重新执行。4. 安全边界与隐私保护设计让AI操作你已登录的浏览器安全是头等大事。Skill设计了三层防护不是简单地“信任AI”而是给它划定了清晰的行动边界。4.1 第一层域名级黑名单硬拦截这是最外层的防护。Skill内置了一个敏感域名列表并支持用户自定义扩展。当AI被要求访问这些域名时会自动降级为“只读模式”。默认黑名单类别金融支付*.bank.com,*.paypal.com,alipay.com,*.chase.com核心认证accounts.google.com,login.microsoftonline.com,*.okta.com云服务控制台console.aws.amazon.com,cloud.google.com,portal.azure.com企业内部敏感系统可由用户通过配置文件~/.browser-control/blocked_domains.txt添加。当检测到目标URL在黑名单内Skill会拒绝执行任何写操作点击、填写、上传仅允许截图和读取页面文本内容并且会在返回结果中明确提示“该页面因安全策略已被限制为只读模式”。4.2 第二层元素级意图识别软防护即使不在黑名单的页面上某些敏感操作也需要被禁止。Skill会对AI解析出的操作指令进行元素级过滤。过滤规则示例密码字段任何type“password”的input元素AI发出的fill命令会被自动忽略。支付/购买按钮通过元素文本、aria-label、># 创建skills目录如果不存在 mkdir -p ~/.claude/skills # 克隆项目 git clone https://github.com/d-wwei/browser-control-skill.git ~/.claude/skills/browser-control这会将所有核心代码、模块和适配器下载到本地。步骤二创建命令软链接Claude Code通过~/.claude/skills/目录下的文件夹名来识别技能。我们需要创建一个软链接让/browse命令指向正确的技能入口。# 进入技能目录 cd ~/.claude/skills # 创建指向browser-control技能内browse子技能的软链接 ln -sf browser-control/skills/browse browse现在Claude Code就能识别/browse命令了。步骤三配置Chrome远程调试这是后台模式CDP能工作的前提。我们需要让Chrome允许外部连接。完全关闭所有Chrome窗口。通过命令行启动Chrome并开启远程调试端口# macOS/Linux /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port9222 # Windows (假设安装在默认路径) “C:\Program Files\Google\Chrome\Application\chrome.exe” --remote-debugging-port9222保持这个命令行窗口打开不要关闭。此时访问http://localhost:9222/json/version如果能看到一串JSON信息说明调试端口已成功开启。步骤四macOS额外权限仅前台模式需要如果你要使用AppleScript前台模式需要授予终端或你的IDE如VS Code控制Chrome的权限。打开系统设置 隐私与安全性 辅助功能。点击左下角锁图标解锁。将你使用的终端应用如Terminal、iTerm2或代码编辑器如Visual Studio Code添加到允许列表中。步骤五验证安装打开Claude Code尝试一个简单命令/browse here 告诉我当前浏览器页面的标题是什么如果一切正常Claude会调用Skill通过AppleScript获取你当前激活的Chrome标签页标题并返回。如果使用后台模式/browse bg 打开 https://httpbin.org/get 并返回页面内容这会通过CDP在后台打开一个标签页获取内容后关闭。5.2 其他AI平台适配要点Skill的架构是平台无关的核心逻辑在skills/browser-control/目录下。对于其他平台你需要的是“适配层”即告诉平台如何调用这些核心能力。OpenAI Codex / ChatGPT自定义GPT将adapters/codex/AGENTS.md文件的内容作为你的Agent系统提示词System Prompt的一部分。这个文件定义了工具Tools的调用规范、输入输出格式以及使用示例。Cursor / Windsurf这两个编辑器内置了AI Agent功能。将adapters/cursor/.cursorrules或adapters/windsurf/.windsurfrules文件复制到你的项目根目录。这些规则文件会指导编辑器内的AI如何调用本地的browse命令脚本。Google Gemini CLI如果你通过命令行与Gemini交互可以参考adapters/gemini/GEMINI.md中的说明配置函数调用Function Calling来触发本地脚本。共通的核心无论哪个平台最终都是调用skills/browser-control/scripts/browse-cmd.sh这个统一的命令行入口。适配器的工作就是把你平台上的自然语言指令转换成这个脚本能理解的参数。5.3 依赖管理与环境检测Skill通过scripts/check-deps.sh脚本自动检测环境。#!/bin/bash # 检查Node.js if ! command -v node /dev/null; then echo “错误未检测到Node.js。后台模式需要Node.js 22。” 2 exit 1 fi # 检查Python3 if ! command -v python3 /dev/null; then echo “警告未检测到Python3。部分高级写操作如文件上传将不可用。” 2 fi # 检查Chrome调试端口 if ! curl -s http://localhost:9222/json/version /dev/null; then echo “正在尝试启动Chrome调试代理...” # 尝试启动内置的代理脚本 node scripts/cdp-proxy.mjs --silent fi首次运行/browse命令时这个脚本会自动执行。如果缺少关键依赖如Node.js它会明确报错。如果Chrome调试端口未开启它会尝试自动启动一个轻量代理但更推荐手动按步骤三的方式启动Chrome更稳定。6. 高级使用场景与排坑实录掌握了基础部署我们来看看一些更复杂的用法和实际使用中必然会遇到的“坑”。6.1 场景自动化跨平台数据收集与录入假设你是一名市场分析师每天需要从10个不同的新闻网站和行业博客收集信息然后整理到Notion的数据库里。传统做法手动一个个打开网页复制粘贴枯燥且易错。使用Browser Control Skill/browse bg 执行以下任务 1. 并行打开以下10个网址[列表] 2. 从每个页面中提取文章标题、发布时间、摘要和原文链接。 3. 打开我们的Notion市场情报数据库页面https://notion.so/...。 4. 为每篇文章在数据库中创建新的一行并填入提取的字段。背后发生了什么主Agent解析指令识别出这是典型的后台并行任务。它派生出10个子Agent每个子Agent通过CDP获得一个独立的targetId各自打开一个标签页去访问指定的网址。每个子Agent使用预定义的或AI实时分析的选择器从页面中抓取所需的结构化数据。所有子Agent完成任务后数据汇总给主Agent。主Agent切换到前台模式因为你已经登录了Notion导航到指定的Notion页面并开始操作数据库视图一行行地创建和填写内容。避坑技巧对于Notion、Airtable这类复杂SPA直接操作DOM可能不稳定。更好的做法是让AI先通过CDP获取页面状态然后通过模拟键盘快捷键如Cmd/Ctrl N新建行Tab切换字段来操作这更接近真人操作成功率更高。Skill的站点经验记忆功能会逐渐学习并记住这些特定站点的最佳操作策略。6.2 场景处理动态加载与验证码现代网页大量使用异步加载和反爬机制。问题一元素还没加载出来AI执行click(‘.load-more-btn’)时按钮可能还没被JavaScript渲染到页面上。解决方案Skill中的所有交互操作都内置了显式等待。上面的点击命令在实际执行时会被包装成“等待选择器.load-more-btn出现且可点击最多等10秒然后点击”。这需要在CDP Helper或AppleScript脚本中实现轮询检查逻辑。问题二遇到Cloudflare Turnstile或hCaptcha验证码这是自动化工具的终极挑战。目前任何自动化方案都无法可靠地绕过真正的验证码。应对策略识别与规避Skill在访问页面时会检查是否有常见的验证码框架元素出现。如果检测到会立即停止操作并向用户报告“页面出现验证码需要人工干预”。会话保持有时验证码只在首次访问或特定操作后出现。Skill会尽量复用已有的浏览器会话Cookie、LocalStorage避免触发验证。人工介入点设计流程时将可能触发验证码的操作如频繁搜索、提交表单作为可选的“断点”。AI可以执行验证码之前的所有步骤然后停下来告诉你“表单已填好请手动完成验证码并点击提交”。6.3 常见问题排查表问题现象可能原因解决方案执行/browse无反应或报“技能未找到”1. 软链接未创建或创建不正确。2. Claude Code技能目录路径不对。1. 检查~/.claude/skills/browse是否为指向browser-control/skills/browse的有效软链接。2. 确认Claude Code的技能加载路径。可以尝试在Claude Code中直接输入!ls skills查看。后台模式命令超时或失败1. Chrome未以调试模式启动。2. 调试端口被占用或代理未运行。3. 网络代理导致CDP连接失败。1. 确保已按步骤三启动Chrome。2. 检查http://localhost:9222/json/version是否可访问。3. 尝试关闭系统代理或VPN。运行scripts/check-deps.sh查看详细错误。前台模式报“应用程序未获得辅助功能权限”macOS的辅助功能权限未授予。前往系统设置 隐私与安全性 辅助功能将你使用的终端或IDE添加到允许列表。需要重启应用。AI点击或填表不生效1. 页面是React/Vue等框架渲染元素选择器失效。2. 操作速度太快页面未响应。3. 元素被遮挡或不可见。1. 尝试使用更稳定的选择器如[data-testid]。让AI先执行截图并标注命令查看它识别出的元素ID。2. 在指令中明确加入等待如“等待2秒后点击提交”。3. 使用scroll_into_view等命令确保元素在视口中。文件上传失败1. 文件路径错误相对路径或~。2. 目标input元素不是type“file”。3. 网站使用了自定义上传组件。1.始终使用绝对路径。可以在指令中写“上传/Users/name/Desktop/file.pdf”。2. 让AI先检查元素属性。3. 对于自定义组件尝试点击其触发元素如“选择文件”按钮来激活系统对话框但这在前台模式下会卡住后台模式无效。这是此类组件的限制。并行任务卡住或混乱多个子Agent竞争同一资源如Cookie或某个子Agent任务失败未释放标签页。1. 确保任务之间相对独立。避免让多个Agent操作同一域名下的敏感会话。2. Skill有超时和清理机制但极端情况下可能需要手动关闭Chrome的调试窗口并重启。6.4 性能优化与最佳实践按需加载模块Skill的modules/目录下的功能模块是懒加载的。只有当你用到截图功能时才会加载截图模块。这保证了技能的启动速度。连接池与复用对于频繁的CDP操作Skill内部维护了一个轻量的连接池避免为每个命令都建立新的WebSocket连接大幅提升后台并行任务的效率。指令尽可能具体给AI的指令越模糊它需要分析和尝试的次数就越多越容易出错。对比差/browse here 填一下这个表。好/browse here 在当前页面的表单中找到‘姓名’输入框可能带有name‘username’或placeholder‘请输入姓名’填入‘张三’找到‘邮箱’输入框填入‘zhangsanexample.com’然后点击绿色的‘提交’按钮。善用站点经验Skill会学习。如果你经常操作某个网站如公司内部的CRM可以将成功的操作模式如稳定有效的选择器、必要的等待时间手动添加到references/site-patterns/下的自定义配置文件中下次AI操作同一网站时会优先采用成功率会显著提升。这个项目的精髓在于它不追求全自动的“黑盒”魔法而是提供了一个强大、可控的“工具箱”将浏览器的操控权以一种安全、可理解的方式交给了AI。你和AI的关系从“它说你做”变成了“你说它做你监督”。这种协作模式才是当下人机协同最务实、也最有潜力的方向。