构建混合浏览器工具包教会了我们什么关于 Web 的知识

61 阅读16分钟

如果您曾经尝试过浏览器自动化,那么您就会知道该怎么做: 您启动 Selenium、Playwright 或 Puppeteer,将其指向某个页面,然后突然间您就会遇到不稳定的选择器、奇怪的屏幕截图或可怕的“未找到元素”,尽管它就在那里。

我经历过那种感觉。感觉就像给机器人一副烤箱手套,教它上网一样。当然,它会点击和滚动,但一半时间都在猜测。

在 CAMEL-AI,我们也遇到了这个问题。我们最初的 Camel BrowserToolkit 是解决这个问题的首次尝试。它完成了一些基本功能——截取屏幕截图、注入自定义 ID 以及点击操作。但它……可以说,不够优雅。它更像是让 AI 点击图片,而不是真正理解页面。

这让我们开始思考: 如果工具包能够像人类一样“看”页面并像开发人员一样理解结构会怎样?

从单体到混合 当我们重新架构时,巨大的转变发生了。我们不再使用单一繁重的 Python 流程,而是使用 Python 和 TypeScript 的混合架构。

Python 仍然是您的脚本层。这意味着您可以使用我们大多数人熟悉的语言编写自动化代码。TypeScript 是底层引擎。它原生运行 Playwright,处理异步操作,并直接与浏览器交互。

两者通过 WebSocket 进行通信。因此,Python 提供高级命令,而 TypeScript 则高效地执行这些命令。

CAMEL 混合浏览器工具包简介 混合浏览器工具包现已推出。我们彻底重建了该工具包,使其成为 TypeScript 和 Python 的混合版本。在新设计中,TypeScript(运行在 Node.js 上)通过 Playwright 快速的原生 API 直接处理浏览器,而 Python 则保留了友好的前端界面。

这能给你带来什么?更快的性能,访问所有最新的 Playwright 功能(例如新的_snapshotForAI),以及真正的异步事件驱动能力——同时又不牺牲 Python 脚本的易用性。

最终形成了一个分层架构:你的 Python 代码通过 WebSocket 与 TypeScript 服务器通信。TypeScript 层负责管理浏览器实例、DOM 查询、屏幕截图等,所有这些都在同一个高性能 JavaScript 环境中进行。Python 只需发送命令并获取结构化结果。

这种拆分意味着更低的延迟和更好的并发性。例如,Node 的 Playwright 不会像 Python 版本那样为每个浏览器窗口生成一个新进程,因此它可以以更少的 CPU 和内存开销管理多个标签页。

简而言之,Python 成为发出高级指令的大脑,而 TypeScript 则是高效完成工作的肌肉。

底层有何不同

在旧版工具包中,每个需要查找或点击元素的操作通常都需要通过脚本向页面注入一个随机 ID,然后进行查询。这种方法虽然有效,但感觉有点老套。

在混合工具包中,我们利用了标准无障碍功能 (ARIA) 选择器和 Playwright 的新工具。现在您可以执行以下操作:

await page.locator('[aria-label="Submit"]').click(); await page.getByRole('button', { name: 'Submit' }).click(); const snapshot = await page._snapshotForAI(); // snapshot now has structured data on all elements and their ARIA roles Playwright _snapshotForAI()(一个内部 API)让我们能够获取丰富的 DOM 快照:每个交互元素、其角色(例如按钮、链接、文本框)、标签等等。我们为每个元素分配一个 ref ID,并将其用于所有交互。这用语义映射取代了旧的随机 ID 技巧。

这也意味着相同的快照数据可以为文本模式和视觉“标记集”屏幕截图提供支持。

标记集截图 说到截图,新工具包的 SoM(标记集)截图功能简洁明了。我们在页面中注入了一个小脚本,用一个小的编号标记(它们的引用 ID)勾勒出每个可点击元素的轮廓。

这不仅仅是一个愚蠢的截图——它能够识别元素重叠,并尽量避免标记隐藏元素。如果按钮包含图标和文本,它会将它们合并为一个标记。它甚至会为标签选择合适的位置,避免它们相互重叠。(这种基于浏览器注入的方法比我们以前仅基于内存的截图更可靠。)

增强隐身模式

我们还增强了隐身模式。默认情况下,Playwright 可以被许多网站检测到(事实上,“普通”的 Playwright 经常被现代反机器人措施屏蔽)。

新的工具包会为浏览器提供全套反检测标志、可自定义的用户代理、标头等。您可以调整StealthConfig对象来精确设置要使用的标志或标头。即使在持久上下文或 CDP 连接中,我们也能保持这些设置。

底线是:您无需额外工作即可获得更像人类的浏览器指纹。

节省内存的截图 其他一些虽小但很实用的改进包括我们处理屏幕截图和图片的方式。在旧工具包中,屏幕截图完全保存在内存中,并以对象的形式传递。现在,我们将屏幕截图保存到磁盘,并且只传递文件路径。

这样可以降低内存占用,尤其是在一次运行中截取大量屏幕截图时。代理仍然可以请求图像(甚至对其进行基于视觉的分析),但大量数据会存储在磁盘上。

更智能的表格填写 我们还使表单填写更加智能。现在,您可以在一个命令中发送多个输入,工具包会尝试找到正确的输入字段(即使您不小心指向了容器)。

它会监视您输入后出现的下拉菜单,并仅返回新的选项(“差异”快照),这样您就不会再被整个页面弄得不知所措。如果出现问题,该工具还会尝试简单的恢复步骤。

主要功能一览 多模式操作:该工具包有三种模式:

文本模式:基于 DOM 的自动化,返回元素列表的文本快照。 可视化模式:基于屏幕截图,突出显示交互元素。 混合模式:根据需要在文本和视觉之间智能切换。 TypeScript 核心:所有浏览器工作均在 Node.js/TypeScript 服务器中完成。这意味着原生 Playwright 调用(无需桥接)以及完整的 async/await 支持。我们能够立即获得 TypeScript 的编译时检查和最新的 API。

更佳的元素处理:使用真实的 ARIA 选择器和 Playwright 定位器,而非注入的 ID。例如,通过 aria-label 或角色点击。此外,_snapshotForAI返回具有语义角色的结构化数据。

即时快照:每个改变页面的操作(单击/输入/等)默认都会返回更新的快照,因此您可以在文本模式下立即看到新状态。

高级截图 (SoM):带注释的截图,每个元素都带有编号标记。AI 还可以选择分析图片(例如“查找所有注册按钮”)。

智能输入:在字段中输入时,系统会自动检测下拉菜单(自动完成),并仅返回新的建议(差异快照)。如果您指向某个容器,系统会找到其中的实际输入并在那里输入。

强大的隐身功能:多个 Chrome 标志、自定义用户代理/标头、持久上下文等,可降低机器人检测率。(毕竟,许多网站都试图实现指纹自动化。) 灵活的连接:您可以通过 Playwright 启动新浏览器,通过 CDP(Chrome DevTools 协议)连接到现有的 Chrome/Edge,甚至可以通过模型上下文协议 (MCP) 连接到 AI 代理。

工具注册表:该工具包将“工具”(操作)与核心巧妙地分离。屏幕截图会保存到文件而非内存中,因此您可以在自定义代理或管道中处理它们,而无需承担巨大的开销。

尝试一下:会话和导航工具 我们来看一些例子。首先,创建一个工具包实例并打开浏览器:

from camel.toolkits import HybridBrowserToolkit

Launch a real browser (non-headless for debugging)

toolkit = HybridBrowserToolkit(headless=False) result = await toolkit.browser_open()

print(result['result']) # "Browser opened." print(f"Tabs: {result['total_tabs']}, Active: {result['current_tab']}") print("Initial Snapshot:", result['snapshot']) 您的第一个调用必须是browser_open()。这将启动 Chromium/Chrome/Edge 并返回默认页面的快照(通常是 about:blank 或您的起始 URL)。您将得到类似以下内容的结果:

Result: Browser opened. Tabs: 1, Active tab index: 0 Initial Snapshot:

  • link "Get Started" [ref=1]
  • link "Documentation" [ref=2]
  • link "GitHub" [ref=3]
  • ... 现在导航:

Open a new tab and navigate to example.com

result = await toolkit.browser_visit_page("example.com") print(f"Visiting example.com: {result['result']}") print("Snapshot:", result['snapshot']) print(f"Tabs now: {result['total_tabs']}, Active: {result['current_tab']}")

Go back and forward

await toolkit.browser_back() # go back in history await toolkit.browser_forward() # then forward again browser_visit_page(url)在新标签页中打开 URL 并切换到该 URL。每次调用都会创建一个新标签页。

browser_back()并browser_forward()在当前标签页的历史记录中移动。它们都返回更新后的页面快照和标签页信息。

例如,访问几个页面后:

await toolkit.browser_visit_page("example.com") await toolkit.browser_visit_page("example.com/about") result = await toolkit.browser_back() print(f"Back: {result['result']}, now at {result['snapshot']}") 页面检查工具

要查看页面上的内容而不执行任何操作,请使用:

snapshot = await toolkit.browser_get_page_snapshot() print(snapshot) 这将返回当前选项卡中所有交互元素(链接、按钮、输入框等)的文本列表,每个元素都带有一个[ref=id]。默认情况下,它会列出整个页面,但您可以使用 进行初始化,viewport_limit=True以便仅显示屏幕上可见的元素。例如:

  • link "Home" [ref=1]
  • button "Sign In" [ref=2]
  • textbox "Search..." [ref=3]
  • link "Products" [ref=4]
  • ... 为了直观的查看,请尝试:

result = await toolkit.browser_get_som_screenshot() print(result['result'])

e.g. "Screenshot captured with 12 interactive elements (saved to: ./screenshots/page123_som.png)"

这会截取页面截图并标记每个元素。你还可以使用工具包通过人工智能进行分析,例如:

result = await toolkit.browser_get_som_screenshot( read_image=True, instruction="Find all buttons for submitting forms" ) print(result['result'])

e.g. "Screenshot captured... Agent analysis: Found 3 form buttons: [ref=5], [ref=9], [ref=12]"

在后台,它保存了一个图像文件,并运行了一个代理(如果需要)来查看它。result['screenshotPath']如果需要,原始图像路径在这里。

要检查标签,请使用:

tab_info = await toolkit.browser_get_tab_info() print(f"Total tabs: {tab_info['total_tabs']}") for tab in tab_info['tabs']: status = " (current)" if tab['is_current'] else "" print(f"- {tab['title']} @ {tab['url']}{status}") 您将看到每个标签页的 ID、标题和 URL。这可以方便您选择要切换到的标签页:

Switch to tab by ID (the 'id' field from tab_info)

await toolkit.browser_switch_tab(tab_id=some_tab_id) 交互工具 现在进行真正的互动:

单击元素 通过引用单击元素:

result = await toolkit.browser_click(ref="5") print(result['result']) # e.g. "Clicked on button 'Submit'" 如果点击打开了新标签页,结果将包含newTabId,并且current_tab/total_tabs也会相应更新。然后您就可以browser_switch_tab访问它了。

在输入字段中输入 输入:

Single input

await toolkit.browser_type(ref="3", text="hello world") 如果 ref=3 的元素触发了自动完成下拉菜单,工具包就会检测到它。它不会再次返回完整页面,而是result['diffSnapshot']只返回新的选项(这就是“智能下拉检测”)。例如,输入“San”可能会返回:

  • option "San Francisco" [ref=23]
  • option "San Diego" [ref=24]
  • option "San Antonio" [ref=25] 然后你可以通过 ref 点击其中一个。如果你有多个字段需要填写,只需传递一个列表即可:

inputs = [ {'ref': '3', 'text': 'John'}, {'ref': '4', 'text': 'Doe'}, {'ref': '5', 'text': 'john.'} ] result = await toolkit.browser_type(inputs=inputs) print(result['details']) # shows success/failure per field 选择下拉菜单 选择(下拉菜单): await toolkit.browser_select(ref="country-select", value="US") 您必须提供选项的 value 属性,而不是可见文本。(如果需要,您可以browser_get_page_snapshot()先查看元素引用。) 输入键 输入密钥(提交表格等): await toolkit.browser_enter() 这模拟了在当前焦点字段中按下 Enter 键。输入搜索词后,此功能非常方便。 滚动 滚动页面: await toolkit.browser_scroll(direction="down", amount=600) 使用“向上”或“向下”按钮,像素数量可选。返回新的快照。您可以循环滚动以加载更多内容: prev = "" while True: res = await toolkit.browser_scroll("down", 800) if res['snapshot'] == prev: break # no new content prev = res['snapshot'] await asyncio.sleep(1) 鼠标控制 通过坐标进行鼠标控制: await toolkit.browser_mouse_control(control="click", x=350.5, y=200) await toolkit.browser_mouse_control(control="dblclick", x=123.4, y=456.7) await toolkit.browser_mouse_control(control="right_click", x=400, y=300) 对于画布或图像地图交互很有用。 拖放 鼠标拖放: await toolkit.browser_mouse_drag(from_ref="item-5", to_ref="trash-bin") 将 ref="item-5" 的元素拖放到 ref="trash-bin" 上。方便在 Web UI 中重新排序或移动文件。 按键 按键/组合键: await toolkit.browser_press_key(keys=["Tab"]) await toolkit.browser_press_key(keys=["Control+a"]) # select all await toolkit.browser_press_key(keys=["Alt+Left"]) # back in history await toolkit.browser_press_key(keys=["F5"]) # refresh 发送任意按键或组合键。该工具包使用 Playwright 的按键语法。 标签管理 使用多个选项卡很容易: 切换标签 按 ID 切换标签页(来自browser_get_tab_info): await toolkit.browser_switch_tab(tab_id=some_tab_id) 这将激活该选项卡并返回其快照。 关闭标签页 关闭标签页: await toolkit.browser_close_tab(tab_id=some_tab_id) 关闭后,它会返回有关剩余选项卡的信息。 例如,您可以通过迭代来关闭除第一个选项卡之外的所有选项卡: tab_info = await toolkit.browser_get_tab_info() for tab in tab_info['tabs']: if not tab['is_current']: await toolkit.browser_close_tab(tab_id=tab['id']) 控制台命令 控制台命令:可以在页面上执行任意JS: result = await toolkit.browser_console_exec("return window.location.href") print("Current URL:", result['result']) 并查看控制台日志: logs = await toolkit.browser_console_view() for msg in logs['console_messages']: print(f"[{msg['type']}] {msg['text']}") 高级 & 实用 等待手动步骤 等待手动步骤:有时您需要人工帮助(例如解决验证码)。使用: res = await toolkit.browser_wait_user(timeout_sec=60) if "completed" in res['result']: print("User resumed, snapshot after:") print(res['snapshot']) else: print("Wait timed out.") 这将暂停执行并显示最后一个快照。当用户按下 Enter 键(或超时)时,它将返回控制权。 结合一切 将它们全部结合起来:这是一个将几个工具组合在一起的小示例: toolkit = HybridBrowserToolkit(headless=False) try: await toolkit.browser_open() await toolkit.browser_visit_page("") # Look for a product link and click it snap = await toolkit.browser_get_page_snapshot() # Suppose ref=7 is "Products" await toolkit.browser_click(ref="7") # Now add to cart and checkout await toolkit.browser_click(ref="add-to-cart") await toolkit.browser_click(ref="checkout") # Fill checkout form inputs = [ {'ref': 'name', 'text': 'Alice'}, {'ref': 'email', 'text': 'alice@example.com'}, {'ref': 'address', 'text': '1 Developer Way'} ] await toolkit.browser_type(inputs=inputs) await toolkit.browser_select(ref="shipping", value="standard") await toolkit.browser_console_exec("return document.querySelector('form').checkValidity()") await toolkit.browser_click(ref="place-order") finally: await toolkit.browser_close() 这只是一个开始。混合浏览器工具包提供了您期望的所有基本导航和交互工具,以及一些强大的附加功能(例如智能屏幕截图和 AI 辅助分析),可帮助您顺利地自动执行复杂的任务。 操作模式:文本、视觉和混合 文本模式是默认模式:每个操作都会返回一个文本快照。它轻量级,非常适合纯数据任务(例如抓取或填写表单)。每个元素都以[ref=ID]和 标签列出。如果您使用 初始化full_visual_mode=True,则操作不会自动返回快照(快速模式);您仍然可以browser_get_page_snapshot()在需要时手动调用。 可视模式使用屏幕截图。browser_get_som_screenshot()我们看到的工具是此模式的核心。它非常适合验证布局、捕捉视觉故障,或者当用户需要查看某些内容时。当您需要确认按钮是否可见,或者向客服人员准确显示屏幕上的内容时,您通常会启用可视模式。 混合模式非常智能:它默认使用文本模式,但在需要时(或根据要求)会无缝截取并解析屏幕截图。例如,您可以在文本模式下点击表单,然后使用 AI 分析截取最后一个屏幕截图,以“抽查”结果。 一个好的经验法则: 使用文本模式实现大多数自动化(快速、无头、易于解析)。 当您需要 UI 上下文时(例如,对于 CAPTCHA、复杂 UI 或人工验证),请切换到可视模式。 根据需要组合两者。例如,在文本模式下点击“参考文献”,然后使用屏幕截图进行验证。 连接模式:Playwright、CDP 和 MCP 最后,我们如何连接到浏览器? 标准剧作家(默认) 该工具包会启动并管理其自身的浏览器实例。只需调用HybridBrowserToolkit()和 即可browser_open()。您可以设置headless=True/False、user_data_dir用于持久化、超时等。如果您只需要一个独立的浏览器,请使用此选项。 Chrome 开发者工具协议 (CDP) 这可以让你连接到已通过 启动的浏览器(Chrome/Edge/Chromium)--remote-debugging-port。例如,手动启动 Chrome: google-chrome --remote-debugging-port=9222 --user-data-dir=/tmp/chrome-profile 然后在 Python 中: import requests resp = requests.get('n') ws = resp.json()['webSocketDebuggerUrl'] toolkit_cdp = HybridBrowserToolkit(cdp_url=ws) No need to call browser_open(); it's already running tab_info = await toolkit_cdp.browser_get_tab_info() print(f"Connected to {tab_info['total_tabs']} tabs") CDP 与 Chrome DevTools 用于与浏览器chromedevtools.github.io通信的协议相同,因此任何启用了调试功能的浏览器都可以被控制。您甚至可以设置cdp_keep_current_page=True让工具包使用当前页面,而不是打开新页面。 MCP(模型上下文协议) 这用于将工具包连接到 AI 助手(例如通过 LLM 连接到 Claude),以便 AI 可以像调用原生函数一样调用这些浏览器工具。设置方法如下: 安装 MCP 服务器 git clone cd browser_agent pip install -e . 配置 Claude 桌面 添加到您的 Claude 配置文件: macOS 系统:~/Library/Application Support/Claude/claude_desktop_config.json 窗户:%APPDATA%\Claude\claude_desktop_config.json { "mcpServers": { "hybrid-browser": { "command": "python", "args": ["-m", "hybrid_browser_mcp.server"] } } } 重启 Claude Desktop 添加配置后,完全重启 Claude Desktop。点击聊天界面的🔌图标即可显示浏览器工具。 可用的浏览器工具 连接后,您将可以访问: 导航:browser_open,browser_visit_page,browser_back,browser_forward 相互作用:browser_click,browser_type,browser_select,browser_scroll 截图:(browser_get_som_screenshot捕获带有可点击元素标记的页面) 标签管理:browser_switch_tab,browser_close_tab 先进的:browser_console_exec,browser_mouse_control 基本用法示例 Claude can now control browsers with simple commands: await browser_open() await browser_visit_page("") await browser_type(ref="search", text="AI automation") await browser_click(ref="submit-button") await browser_get_som_screenshot() await browser_close() 定制 修改浏览器行为browser_agent/config.py: BROWSER_CONFIG = { "headless": False, # Show browser window "stealth": True, # Avoid bot detection "enabled_tools": [...] # Specify which tools to enable } 结束语 总而言之,混合浏览器工具包 (Hybrid Browser Toolkit) 是对旧版仅支持屏幕截图的 BrowserToolkit 的重大升级。我们仍然提供友好的 Python API,但底层使用的是浏览器原生的 TypeScript 语言。 这意味着更快、更可靠的交互,以及 Playwright 无障碍快照等全新功能。无论您需要闪电般的 DOM 抓取,还是类似人眼的视觉检查(或两者兼而有之!),这款工具包都能满足您的需求。 它也能与现代工作流程完美兼容。想要连接到现有的 Chrome 浏览器?没问题(感谢 CDP)。想要你的 AI 代理浏览网页?请查看 MCP 集成。 从实用导航(单击、键入、滚动)到高级技巧(标记集屏幕截图、智能自动完成键入、多选项卡管理),一切都在这里。 试用一下,告诉我们您用它构建了什么。欢迎来到 CAMEL 混合浏览器工具包带来的浏览器自动化新时代——就像脱下手套,全速驾驶,精准掌控。查看更多https://www.youjiutian.com