BrowserUse01-源码-Actor模块
Actor模块
模块一:当前文件夹核心内容梳理
1.1 核心知识极简概括
- 基于CDP协议构建类似Playwright的Web自动化库:封装Chrome DevTools Protocol底层调用,提供面向对象的高级API,屏蔽复杂性。
- 统一的元素交互抽象层:将DOM元素操作抽象为Element类,提供click、fill、hover等通用方法,处理浏览器兼容性和稳定性问题。
- 页面级操作与状态管理:通过Page类封装页面导航、JavaScript执行、截图等操作,维护页面状态和会话管理。
- 鼠标操作精确控制:提供Mouse类实现基于坐标的精确鼠标控制,支持点击、移动、滚动等底层操作。
- AI增强的元素识别与内容提取:集成LLM能力,通过自然语言提示定位元素和提取结构化内容。
1.2 子知识扩展
基于CDP协议构建类似Playwright的Web自动化库
- 会话管理机制:BrowserSession负责浏览器实例的启动、停止和生命周期管理,维护CDP连接和会话状态。
- CDP命令封装:将复杂的CDP命令序列封装成简单的API调用,如navigate、evaluate、screenshot等方法。
- 异步操作处理:所有操作基于async/await模式,确保高并发场景下的性能和稳定性。
- 错误处理与恢复:实现多种fallback机制,在主要操作失败时自动尝试备选方案。
- 多标签页支持:支持创建、管理和切换多个浏览器标签页,提供类似真实浏览器的体验。
统一的元素交互抽象层
- 元素定位策略:通过backendNodeId唯一标识DOM元素,避免传统XPath/CSS选择器在动态页面中的不稳定问题。
- 多种点击实现:提供基于CDP、JavaScript和坐标计算的多重点击机制,确保在各种场景下都能成功点击元素。
- 文本输入优化:实现人性化的文本输入模拟,支持修饰键、特殊字符和逐字符输入,提高输入成功率。
- 属性获取方法:提供获取元素属性、边界框、基本信患等多种方法,便于元素状态检测和操作。
- 元素状态同步:在操作前后自动同步元素状态,确保操作的准确性和一致性。
页面级操作与状态管理
- 导航控制:实现完整的浏览器导航功能,包括前进、后退、刷新和直接跳转到指定URL。
- JavaScript执行环境:提供安全的JavaScript执行环境,支持参数传递和复杂表达式求值。
- 视口管理:支持动态调整浏览器窗口大小和视口设置,适配不同分辨率需求。
- 页面信息获取:提供获取页面URL、标题等基本信息的方法,便于状态监控和验证。
- 截图功能:支持全页面和元素级截图,支持多种图片格式和质量设置。
鼠标操作精确控制
- 坐标系管理:维护统一的坐标系,确保鼠标操作在正确的位置执行。
- 多按钮支持:支持左键、右键、中键等多种鼠标按钮操作。
- 滚动实现:提供多种滚动方式,包括鼠标滚轮事件和JavaScript滚动。
- 移动轨迹模拟:支持平滑的鼠标移动轨迹,模拟真实用户操作。
- 事件序列控制:严格按照鼠标按下、移动、释放的顺序执行,确保操作的正确性。
AI增强的元素识别与内容提取
- 自然语言元素定位:通过LLM理解自然语言描述,自动匹配页面上的对应元素。
- 结构化内容提取:利用LLM从页面内容中提取结构化数据,支持自定义数据模型。
- DOM树序列化:将复杂的DOM树结构序列化为LLM友好的文本表示。
- Prompt工程优化:精心设计的系统提示词,引导LLM准确理解和执行任务。
- 结果验证机制:对LLM返回的结果进行验证,确保元素索引的有效性和准确性。
1.3 知识点详细说明
基于CDP协议构建类似Playwright的Web自动化库
这个模块的设计目标是提供一个类似于Playwright但更轻量级的Web自动化解决方案,基于Chrome DevTools Protocol(CDP)实现。核心思想是将复杂的CDP命令封装成简单易用的API,让开发者能够专注于业务逻辑而非底层实现细节。
架构设计
模块采用分层架构设计,BrowserSession作为核心会话管理器,负责与浏览器实例建立连接并管理会话生命周期。Page类代表一个浏览器标签页或iframe,提供页面级别的操作接口。Element类封装了DOM元素的相关操作,Mouse类提供了基于坐标的鼠标操作能力。
BrowserSession Page Page Page Element Element Mouse Element Element
会话管理机制
BrowserSession负责管理浏览器实例的整个生命周期。它通过CDP客户端与浏览器建立连接,并维护会话状态。在启动时,会初始化必要的CDP域(如Page、DOM、Runtime等),确保后续操作能够正常执行。
CDP命令封装
为了简化CDP命令的使用,模块将复杂的命令序列封装成单一的方法调用。例如,点击元素操作可能涉及获取元素位置、滚动到可视区域、分发鼠标事件等多个步骤,但对外只暴露一个简单的click方法。
错误处理与恢复
考虑到Web自动化环境的复杂性,模块实现了多种错误处理和恢复机制。当主要操作失败时,会自动尝试备选方案。例如,在元素点击失败时,会尝试使用JavaScript直接触发点击事件。
统一的元素交互抽象层
Element类是整个模块的核心组件之一,它将DOM元素的各种操作封装成统一的接口。通过backendNodeId唯一标识元素,避免了传统选择器在动态页面中的不稳定性问题。
元素定位策略
传统的Web自动化工具通常使用XPath或CSS选择器来定位元素,但在现代SPA应用中,页面结构经常发生变化,导致选择器失效。本模块采用backendNodeId作为元素的唯一标识,这是一种由浏览器内部维护的稳定标识符,不会因为页面结构变化而改变。
多种点击实现
点击操作是Web自动化中最常用的交互之一,但也最容易出现问题。模块实现了三种点击机制:
- 基于CDP的点击:通过DOM.getContentQuads获取元素位置,然后分发鼠标事件
- 基于盒模型的点击:当getContentQuads不可用时,使用DOM.getBoxModel作为备选方案
- 基于JavaScript的点击:当以上两种方法都失败时,直接调用元素的click方法
这种多层次的实现确保了在各种复杂场景下都能成功点击元素。
文本输入优化
文本输入操作需要考虑很多细节,如修饰键处理、特殊字符输入、输入法兼容等。模块实现了人性化的文本输入模拟,能够正确处理各种字符和修饰键组合。
页面级操作与状态管理
Page类提供了页面级别的操作接口,包括导航控制、JavaScript执行、截图等功能。它是连接BrowserSession和Element的桥梁,负责协调各种页面操作。
导航控制
模块实现了完整的浏览器导航功能,包括:
- 前进/后退:通过Page.getNavigationHistory获取历史记录,然后导航到指定条目
- 刷新:重新加载当前页面
- 直接跳转:导航到指定URL
所有导航操作都会等待页面加载完成,确保后续操作能够在正确的状态下执行。
JavaScript执行环境
模块提供了一个安全的JavaScript执行环境,支持参数传递和复杂表达式求值。通过Runtime.evaluate命令执行JavaScript代码,并自动处理结果序列化。
鼠标操作精确控制
Mouse类提供了基于坐标的精确鼠标控制,支持点击、移动、滚动等底层操作。它是实现复杂交互(如拖拽、悬停等)的基础。
坐标系管理
模块维护统一的坐标系,确保鼠标操作在正确的位置执行。所有坐标都是相对于视口的绝对坐标,避免了相对坐标计算的复杂性。
AI增强的元素识别与内容提取
模块集成了LLM能力,通过自然语言提示定位元素和提取结构化内容,这是与其他Web自动化工具的重要区别。
自然语言元素定位
通过LLM理解自然语言描述,自动匹配页面上的对应元素。这一功能极大地简化了元素定位的复杂度,开发者只需用自然语言描述想要操作的元素即可。
模块二:核心代码逻辑
2.1 核心类/方法速查表
| 类/方法名 | 定位(文件:行号) | 输入输出 | 使用场景示例(1句话) | 调试提示(如:断点打在哪) |
|---|---|---|---|---|
| BrowserSession | page.py |
管理浏览器会话 | 创建和管理浏览器实例 | 在_session_id属性处打断点 |
| Page | page.py:30 |
页面操作接口 | 导航到指定URL或执行JavaScript | 在evaluate方法处打断点 |
| Element | element.py:30 |
元素操作接口 | 点击按钮或填写表单 | 在click方法的多重策略处打断点 |
| Mouse | mouse.py:15 |
鼠标操作接口 | 在指定坐标点击或滚动页面 | 在click方法处打断点 |
| Element.click() | element.py:70 |
无返回值 | 点击页面上的某个元素 | 在获取四边形坐标处打断点观察策略选择 |
| Element.fill() | element.py:200 |
无返回值 | 在输入框中填入文本 | 在_clear_text_field方法处打断点 |
| Page.evaluate() | page.py:150 |
JavaScript执行结果 | 执行JavaScript代码获取页面信息 | 在_fix_javascript_string方法处打断点 |
2.2 最小复现示例(伪代码)
python
# ①依赖注入
browser_session = BrowserSession() # 创建浏览器会话
llm = MockLLM() # 模拟语言模型
# ②关键调用
await browser_session.start() # 启动浏览器
page = await browser_session.new_page("https://example.com") # 创建新页面
# 通过CSS选择器获取元素
elements = await page.get_elements_by_css_selector("button.submit")
# 通过自然语言获取元素
element = await page.get_element_by_prompt("登录按钮", llm)
# 元素交互
if element:
await element.click() # 点击元素
await element.fill("Hello World") # 填入文本
# 执行JavaScript
title = await page.evaluate("() => document.title")
# 截图
screenshot = await page.screenshot()
# ③断言验证
assert len(elements) > 0 # 验证元素获取成功
assert title == "Example Domain" # 验证页面标题
assert len(screenshot) > 0 # 验证截图成功
