BrowserUse06-源码-DOM模块

DOM 模块
模块一:当前文件夹核心内容梳理
1.1 核心知识极简概括
- 多源数据融合的DOM树构建:整合CDP的DOM树、Accessibility树和DOM快照数据,构建增强型DOM树节点,提供全面的元素信息。
- 智能元素筛选与序列化:通过可点击元素检测、绘制顺序优化和边界框过滤等算法,筛选出对LLM有价值的交互元素并序列化。
- 跨框架内容处理:支持处理iframe和Shadow DOM内容,构建统一的DOM树表示,确保跨框架元素的正确识别。
- 复合控件抽象:识别并抽象常见的复合控件(如下拉选择、文件上传、音频视频播放器等),为LLM提供清晰的交互模型。
- 高性能DOM分析引擎:通过缓存、延迟加载和并行处理等优化手段,实现快速的DOM树构建和序列化。
1.2 子知识扩展
多源数据融合的DOM树构建
- 数据来源:从Chrome DevTools Protocol获取三类核心数据:DOM树结构、Accessibility可访问性信息、DOM快照(包含布局和样式信息)。
- 增强节点构造 :EnhancedDOMTreeNode类整合了来自DOM、AX和快照的数据,提供完整的元素信息。
- 跨框架处理 :支持处理iframe和Shadow DOM,通过frame_id和parent_node维护完整的节点关系。
- 可见性计算:综合考虑CSS样式、滚动位置和框架嵌套关系,准确计算元素在视口中的可见性。
- 异常处理:对跨域iframe和无法访问的数据进行优雅处理,避免中断整个构建过程。
CDP数据源 DOM树 Accessibility树 DOM快照 增强DOM节点 完整DOM树结构
智能元素筛选与序列化
- 可点击元素检测 :ClickableElementDetector通过DOM属性、AX角色和样式等多种方式识别可交互元素。
- 绘制顺序优化 :PaintOrderRemover根据元素的绘制顺序过滤被遮挡的元素,避免向LLM提供不可见的交互元素。
- 边界框过滤 :通过_apply_bounding_box_filtering方法过滤被父容器完全包含的元素,减少冗余信息。
- 简化树构建 :_create_simplified_tree方法创建适合序列化的简化树结构,去除无用节点。
- 多种序列化格式 :支持为不同场景提供不同的序列化格式,如DOMEvalSerializer和DOMCodeAgentSerializer。
复合控件抽象实现细节
- 控件识别:通过元素类型和属性识别常见的复合控件,如日期选择器、文件上传、下拉选择等。
- 虚拟组件生成 :为复合控件生成虚拟的子组件信息,如为file输入生成"浏览文件"按钮和"文件已选择"文本框。
- 状态信息提取:从AX树和其他数据源提取控件的当前状态信息,如文件选择器的已选文件名。
- 交互模型抽象:将复杂的复合控件抽象为简单明了的交互模型,便于LLM理解和操作。
- 格式提示生成:根据控件的值格式自动生成提示信息,帮助LLM正确输入数据。
1.3 知识点详细说明
DOM服务核心流程
DOM模块的核心是DomService类,它负责从浏览器获取原始数据并构建增强的DOM树。
主要流程:
- 通过CDP获取DOM树、Accessibility树和DOM快照
- 构建增强的DOM节点,整合多源数据
- 处理iframe和Shadow DOM内容
- 计算元素可见性和其他属性
- 序列化为适合LLM使用的格式
DomService Chrome DevTools EnhancedDOMTreeNode DOMTreeSerializer 请求DOM数据 返回DOM/AX/快照数据 构建EnhancedDOMTreeNode 处理iframe和Shadow DOM 传递增强DOM树 元素筛选和优化 返回序列化结果 DomService Chrome DevTools EnhancedDOMTreeNode DOMTreeSerializer
序列化器架构设计
DOM模块采用了多种序列化器来适应不同使用场景:
- DOMTreeSerializer:主要序列化器,用于Agent与LLM交互
- DOMEvalSerializer:用于评估场景的序列化器
- DOMCodeAgentSerializer:用于Code Agent的序列化器
每种序列化器都有特定的优化目标和输出格式,但都基于同一个增强DOM树。
可见性计算算法
元素可见性是DOM处理中的关键问题,模块通过以下步骤计算:
- 基础可见性检查:检查CSS的display、visibility和opacity属性
- 框架可见性传播:考虑iframe嵌套关系和滚动位置对可见性的影响
- 边界交叉检测:计算元素边界与视口边界的交叉情况
- 滚动位置调整:根据文档的滚动位置调整元素的实际可见区域
这个算法确保了即使在复杂的iframe嵌套和滚动情况下,也能准确判断元素的可见性。
模块二:核心代码逻辑
2.1 核心类/方法速查表
| 类/方法名 | 定位(文件:行号) | 输入输出 | 使用场景示例(1句话) | 调试提示(如:断点打在哪) |
|---|---|---|---|---|
DomService.get_dom_tree() |
service.py:263 | target_id → EnhancedDOMTreeNode | 获取指定目标页面的完整DOM树结构 | 在方法开始和返回前打断点,观察DOM树构建过程 |
DomService.get_serialized_dom_tree() |
service.py:515 | 无 → SerializedDOMState | 获取供LLM使用的序列化DOM表示 | 在序列化开始和结束处打断点,检查序列化结果 |
DOMTreeSerializer.serialize_accessible_elements() |
serializer.py:100 | EnhancedDOMTreeNode → SerializedDOMState | 将DOM树序列化为LLM友好的字符串格式 | 在各个处理步骤之间打断点,观察中间状态变化 |
EnhancedDOMTreeNode |
views.py:325 | 多源数据 → 增强节点 | 表示一个整合了多源信息的DOM节点 | 在构造函数处打断点,检查数据融合过程 |
ClickableElementDetector.is_interactive() |
clickable_elements.py:34 | EnhancedDOMTreeNode → bool | 判断一个元素是否可交互 | 在方法开始和各个判断条件处打断点,分析判断逻辑 |
2.2 最小复现示例(伪代码)
python
# ①依赖注入
browser_session = BrowserSession() # 浏览器会话
dom_service = DomService(browser_session) # DOM服务
# ②关键调用
# 获取增强DOM树
enhanced_dom_tree, timing = await dom_service.get_dom_tree(target_id="some_target_id")
# 序列化为LLM可理解格式
serialized_state, enhanced_tree, timing = await dom_service.get_serialized_dom_tree()
# ③断言验证
assert isinstance(enhanced_dom_tree, EnhancedDOMTreeNode) # 检查DOM树类型
assert hasattr(enhanced_dom_tree, 'ax_node') # 检查是否包含AX信息
assert len(serialized_state.selector_map) > 0 # 检查是否识别到可交互元素
# 使用序列化结果
llm_readable_dom = serialized_state.llm_representation()
print(llm_readable_dom) # 输出供LLM阅读的DOM结构