【科普】灵犀专业版官方内置Browser技能、浏览器连接器与灵犀浏览器助手

快乐小子新
快乐小子新 Lv.2 潜力创作者

Lv.2潜力创作者

WPS灵犀官方内置browser技能的引擎从nodriver变更为cdp-use

灵犀浏览器助手正式上线

灵犀专业版目前已正式推出浏览器连接器和灵犀浏览器助手,本文对此进行深度解析。

一、概述

用户向灵犀发出指令——"打开 bbs.wps.cn,捕获首页帖子标题"。该指令触发一条完整的操作链路,按顺序涵盖以下环节:

  1. 加载 Browser 技能模块

  1. 获取一个可用的浏览器实例

  1. 导航到目标 URL

  1. 等待页面渲染完成

  1. 提取页面快照,解析帖子标题

  1. 返回结果

本文沿着这条操作链路逐站拆解。

1.1 技能加载

Browser 技能通过 import browser 加载。该语句并非导入一个标准的 Python 包,而是通过灵犀运行时注入的 SKILL_PATH 环境变量定位技能目录,再拼接 browser/scripts 子路径后加入 sys.path,最终加载该目录下的 browser.py

sys.path.insert(0, os.path.join(os.getenv("SKILL_PATH"), "browser", "scripts"))
import browser

SKILL_PATH 由灵犀桌面端在启动时注入到 Python 进程的环境变量中,指向技能存储目录。脱离灵犀环境时该变量不存在,Browser 技能无法独立加载——这是它与灵犀运行时深度绑定的核心特征。

加载 browser.py 时,Python 依次导入以下依赖模块:

文件

职责

browser.py

模块入口,定义 navigate、click、fill 等九大公开 API

api.py

API 实现层,编排每个操作的具体流程

core.py

CDP 客户端封装,Browser 类的核心实现

cdp_http.py

HTTP CDP 客户端,用于 Extension 模式下的命令转发

util.py

工具函数,核心为 get_browser()——浏览器初始化与缓存管理

extensions/snapshot.py

快照扩展,负责提取页面元素与文本

加载完成后,browser 对象暴露九个方法,覆盖网页交互的完整生命周期:页面导航、元素点击、表单填写、文件上传、下拉选择、JS 执行、截图、用户手动接管,以及元素列表刷新。


二、浏览器获取:双模式与降级链

任务序列的第 2 步是获取可用的浏览器实例。执行 browser.navigate(url) 后,首先调用 get_browser() 完成该任务。该函数遵循两条路径,形成优先级明确的降级链。

2.1 Extension 模式(插件模式)

当灵犀浏览器助手插件已安装时,通过该插件控制用户正在使用的浏览器(Edge 或 Chrome)。

通信链路

Python 层 → HTTPCDPClient → native-host(http://127.0.0.1:38127/cdp)
         → 浏览器插件 → 浏览器标签页

HTTPCDPClient 将 CDP 命令封装为 HTTP POST 请求,发送给本地 native-host 服务。native-host 解析后转发给浏览器插件,插件再通过 chrome.debugger API 在目标标签页上执行。该模式下,用户可以看到浏览器窗口中的操作过程,且浏览器保留用户登录态与 Cookie。

2.2 CDP 模式(无头模式)

当插件未安装时,系统自动降级。Go 侧 localserver 启动灵犀内置的 ungoogled-chromium 浏览器,通过 --remote-debugging-port 参数开启远程调试端口,通过 WebSocket 直连控制。

通信链路

Python 层 → CDPClient(WebSocket)→ Chromium 远程调试端口

所用浏览器为 ungoogled-chromium(去 Google 服务依赖的 Chromium 发行版)。该模式下浏览器默认无界面运行(headless),用户不可见。

2.3 降级链

Extension 模式(插件)
  → 插件不可用?降级到 CDP 模式(内置 Chromium)
    → Chromium 不存在?返回错误:浏览器可执行文件不可用

2.4 两种模式对比

对比维度

Extension 模式

CDP 模式

浏览器来源

用户日常浏览器(Edge/Chrome)

内置 ungoogled-chromium

通信方式

HTTP → native-host → 插件 → CDP

WebSocket 直连 CDP

用户可见性

可见

无头模式,不可见

登录态

保留用户浏览器登录态

全新空白会话

前置依赖

需安装灵犀浏览器助手插件

2.5 模式切换规则

browser.mode 属性控制模式选择,接受 "extension""headless" 两个值。模式仅在设置它的当前轮对话中有效,下一轮对话自动重置为 "extension"。此机制通过 _get_mode() 函数中基于 BROWSER_RUN_ID 的跨轮检测实现,确保每次对话从默认模式开始,避免因跨轮残留导致意外行为。


三、页面导航与渲染等待

获取浏览器实例后,任务序列进入第 3 步:导航到目标 URL。api.navigate() 编排以下 CDP 命令序列:

1. Browser.getVersion          → 健康检查,确认浏览器连接可用
2. Target.createTarget         → 创建空白标签页(about:blank)
3. Target.attachToTarget       → 附加到该标签页,获取 sessionId
4. Page.navigate               → 导航到目标 URL

导航完成后进入第 4 步:等待页面渲染完成。系统不会立即抓取页面内容,而是执行渲染等待策略,确保页面 JS 动态注入的内容已呈现:

  1. DOMContentLoaded 等待:等待 window.load 事件触发,确保静态资源加载完成

  1. DOM 稳定性检测:轮询 document.body.innerText.length 与可交互元素数量,连续多次检测结果不再变化时认为渲染稳定

  1. 超时兜底:最长等待数秒,避免无限阻塞

该策略的实现在 util.wait_dom_stable() 中:以 400ms 为间隔轮询,连续 2 次无变化即判定稳定,最长等待 3 秒。


四、页面快照与元素索引机制

渲染稳定后,任务序列进入第 5 步:提取页面快照。系统调用快照扩展 extensions/snapshot.py,通过执行 extract_elements.js 提取页面结构,返回结构化文本快照。快照包含三个部分:

1. 页面元信息:Title、URL

2. 可交互元素列表:每个元素分配一个整数索引,格式如下:

Interactive elements (index[:]info):
 24[:] a href="/topic/93816" | 🚀 【WPS社区速递】本周热议...
 29[:] a href="/topic/93786" | 【社区BB机】2026.8.7...
 35[:] a href="/topic/93794" | 📸【小表姐的暑期旅行日记·第4期】投票!

3. 页面可见文本:页面中所有可见的文本内容

通过元素索引引用页面元素,无需理解 HTML、CSS 选择器或 DOM 结构。例如,点击索引 24 的帖子链接:

browser.click(element_index=24)

click 方法内部执行以下操作:滚动到目标元素、等待元素稳定、执行点击、返回新的页面快照。当页面动态加载新内容后,调用 get_interactive_elements() 刷新元素列表与索引。

当页面内容超过 10,000 字符或元素超过 100 个时,超出部分自动保存到本地文件,快照中提示文件路径。


五、API 操作方法

所有 API 遵循统一的输入输出模式:传入索引(或参数)→ 执行操作 → 返回结构化文本快照

方法

功能

典型场景

navigate(url)

打开页面

访问目标网站

click(element_index)

点击元素

按钮、链接、选项

fill(element_index, text, press_enter)

填写输入框

搜索框、表单字段

upload_files(element_index, files)

上传本地文件

简历上传、图片提交

select_option(element_index, ...)

下拉框选择

按文本/值/索引匹配

get_interactive_elements()

刷新元素列表

动态加载后更新索引

execute_script(script)

执行 JavaScript

获取页面深层数据

screenshot(output, full_page)

页面截图

视觉验证、证据留存

request_manual()

弹出浏览器让用户手动操作

登录、验证码、扫码

fill 方法的实现细节:先点击目标输入框使其聚焦,清空 value 属性,再通过 insertText CDP 命令填入文本。若 press_enter=True,则在填入后触发 Enter 按键事件。

upload_files 方法接受文件路径列表,校验文件存在性、可读性及目标控件的 accept 属性,通过 CDP 的 DOM.setFileInputFiles 或文件选择器拦截通道将文件交付给页面。


六、人机协作机制

当自动化遇到不可逾越的障碍时,系统暂停操作并请求用户介入。触发条件包括:页面要求登录、出现验证码、要求扫码、被 Cloudflare 等安全防护拦截。

处理流程:

自动化暂停 → 向用户说明障碍类型
  → 调用 ask_user_question 工具提供选项:
      ① 弹出浏览器,用户手动操作
      ② 用户提供账号密码
      ③ 放弃
  → 用户选择后执行

若用户选择"弹出浏览器",调用 browser.request_manual()request_manual() 通过 _request_browser_manual() 向 Go 侧发送 __BRWS_MAN__ 请求,Go 侧启动一个有头浏览器窗口让用户操作。用户完成操作后通知继续执行,先调用 get_interactive_elements() 获取当前页面快照,再决定后续步骤。

二维码处理规则:禁止截图二维码传输给用户,因二维码存在有效期,截图传输过程中极易过期。正确做法是调用 request_manual() 弹出浏览器,让用户在本机实时扫码。


七、浏览器实例的生命周期管理

浏览器实例在 util._browser 全局变量中缓存,同一轮对话中的连续操作复用同一实例,避免重复初始化。缓存在以下情况被清理:

  • mode 变化browser.mode 值变更时,_browser_browser_mode 均置为 None

  • 健康检查失败:每次操作前调用 is_healthy() 通过 Browser.getVersion 检测浏览器是否存活,若不可达则清除缓存

  • 跨轮对话BROWSER_RUN_ID 变化时,_get_mode() 检测到 mode 为上一轮设置,自动重置并清除缓存


八、总结

Browser 技能的核心设计理念是"通过元素索引实现与网页的交互,屏蔽底层 HTML 结构复杂度",其技术架构如下:

  1. 双模式浏览器获取:Extension 模式(用户浏览器 + 插件)与 CDP 模式(内置 Chromium),通过自动降级链确保至少一种可用

  1. 结构化快照:每次操作返回元素索引列表与页面文本,供解析和决策

  1. 元素索引交互:通过整数索引引用页面元素,无需 CSS 选择器或 DOM 操作知识

  1. 人机协作兜底:登录、验证码等自动化瓶颈通过 request_manual() 移交用户处理

在实际使用中,Browser 技能作为搜索工具的补充,解决实时数据获取、站内深度检索、表单交互等需要真实浏览器渲染能力的场景。其设计在自动化效率与可靠性之间取得了平衡——自动化覆盖常规操作,人机协作兜底异常情况。

广东省
浏览 593
1
6
分享
6 +1
1 +1
全部评论