返回知识中心
入门

CDP 输入合并:保持悬停交互的一致性

决定何时为单个上下文启用 CDP 鼠标悬停合并,验证可见结果,并让点击、拖拽、滚轮、键盘、触摸和触控笔输入保持正常路径。

BotBrowser Team

文档中心

想直接进入 入门 文档吗?

这篇文章属于知识中心的指南库。若你要步骤化配置、参考说明和持续更新,请直接进入对应 docs 分区。

浏览器自动化客户端通常一次发送一个 CDP 鼠标移动命令。客户端发送一个坐标,等待命令完成,再发送下一个坐标。这种顺序容易推理,也很适合点击,但一条较长的悬停路径会变成一串彼此孤立的移动。会响应指针的界面,例如工具提示、悬停卡片以及指针靠近时展开的菜单,可能因这些移动到达浏览器输入处理的方式不同而表现不同。

BotBrowser 为悬停密集的工作负载提供了一个上下文级选项:--bot-cdp-coalesce。该选项默认关闭。为 BrowserContext 开启后,通过 CDP 发送的纯鼠标悬停移动会按顺序分成短序列分组,再由 Chromium 投递。每一个坐标仍由你的客户端选择。点击、拖拽、滚轮、键盘、触摸、触控笔和相对移动输入保持正常路径。实际要回答的问题是:何时开启该选项,如何按上下文设置,以及如何在不依赖固定事件数量的前提下判断结果。

示意图:CDP 客户端把按顺序的悬停坐标发送到浏览器上下文,短序列在到达浏览器之前被分组,而点击、拖拽、滚轮、键盘、触摸和触控笔输入保持正常路径

要点

  • 除非上下文有明确记录的鼠标悬停需求,否则保持该选项关闭。
  • 在创建第一个页面前设置,并用相同路径进行成对运行比较。
  • 判断可见的悬停结果和后续动作,不要依赖固定的页面事件数量。

内容导航

从默认设置开始

大多数浏览器自动化不需要特殊的输入设置。工作负载依赖点击、表单填写、键盘导航、滚动、拖放、触摸手势或触控笔时,请保持该选项关闭。默认设置保留 CDP 命令正常的完成行为,不会改动已经满足交互要求的流程。

只有当某个上下文通过 CDP 频繁发送纯鼠标悬停移动,并且需要这些坐标以短而有序的分组投递时,才开启该选项。典型场景包括工具提示检查、指针靠近时展开的菜单、悬停卡片,以及对指针敏感的桌面界面。该设置属于上下文,因此一个工作负载可以使用它,而同一浏览器中的另一个上下文继续使用默认值。

该选项不会让指针路径变得随机,也不会创造移动坐标。坐标及其顺序仍由你的客户端决定。BotBrowser 只改变已接受的悬停移动在一个短序列中如何被转发,最后一个坐标仍是页面看到的最终位置。如果客户端产生的路径稀疏或包含突然跳变,应在客户端修正,因为该选项不会改变轨迹质量。

按工作负载做决定时,要看具体旅程,而不是整个集群。统计旅程中的纯悬停移动,检查界面响应的是指针靠近而不是点击,并问一问默认设置是否已经能稳定产生可见状态。如果悬停状态能稳定达到,就没有理由改动设置。如果只是偶尔达到,先检查目标几何位置、页面就绪状态和客户端坐标,然后在单独的上下文中试用该选项,并比较两次运行。

配置一个 BrowserContext

在 BotBrowser 启动器提供的上下文配置入口中设置 --bot-cdp-coalesce,并在上下文创建第一个页面之前应用。把该值与浏览器版本、所选 profile 和自动化包版本一起保存,以便之后的验证能够复现同一输入策略。

单独的 flag 即表示开启,显式写成 --bot-cdp-coalesce=true 效果相同。当共享部署模板可能加入该 flag,而某个上下文必须保持默认行为时,使用 --bot-cdp-coalesce=false。把这个值当作上下文配置的一部分,而不是在上下文已经服务页面时再去切换的东西。

const client = await browser.target().createCDPSession();
const context = await browser.createBrowserContext();

await client.send('BotBrowser.setBrowserContextFlags', {
  browserContextId: context._contextId,
  botbrowserFlags: ['--bot-cdp-coalesce'],
});

上面的示例来自 Automation Consistency 参考文档,只为一个上下文开启该选项。请在调用返回之后,再在该上下文中创建第一个页面。

当一个浏览器承载多个上下文时,为每个上下文设置明确的值。开启了该选项的上下文不会替同级上下文开启,新建的上下文必须获得自己的值。这种隔离让团队可以在同一个浏览器内,对同一段旅程比较开启与未开启该行为的结果。

把设置放在启动配置中保持可见,而不是藏在页面代码里,并在运行元数据中记录它是开启还是关闭。页面脚本不能替代该选项,因为它们无法改变 CDP 鼠标命令的投递方式。

上下文重建时,需要再次应用该选项。进程级模板可以方便地重复所需的值,但该行为仍然是按上下文做出的选择。对于让同一个浏览器服务不同账号、租户或获授权测试会话的系统,这一点尤其重要,每个上下文都应携带其自身流程所记录的输入策略。

导航也是一个有用的边界。在一个文档上开始的悬停并不能解释替换文档上的指针行为,所以要等新页面就绪,再执行新界面所需的移动。如果页面或目标在移动流中途被替换,应开始新的旅程,而不是延续旧的旅程。

选项覆盖的范围

只有纯鼠标悬停移动符合条件。具体来说,没有任何按钮被按下,指针不处于相对移动模式,事件是普通的鼠标移动。这涵盖了接近目标、检查悬停状态或穿过桌面界面时使用的移动。

以下输入保持正常路径:

  • 鼠标按钮的按下与抬起事件。
  • 活动中的拖拽移动和拖拽状态转换。
  • 滚轮输入。
  • 键盘输入和文本输入。
  • 触摸输入。
  • 触控笔输入。
  • 相对鼠标移动。

这些边界保护那些承载离散动作或属于其他设备类型的输入。点击保留其按钮状态和完成行为,拖拽保留其状态转换的顺序,滚轮事件保留其增量和时序语义。移动端和触摸旅程应使用触摸输入和移动视口来评估,触控笔界面应使用触控笔输入,相对移动应用则走其正常路径,因为鼠标悬停设置不能替代这些测试。

按钮状态很重要。按住按钮时到达的移动属于拖拽或其他活动的指针操作,因此它不是纯悬停,会继续走正常路径。这条规则避免悬停分组跨过指向控件与操作控件之间的边界。在 CDP 对 Input.dispatchMouseEvent 的参考文档中,悬停是没有按住按钮的 mouseMoved 事件,这正是该选项所关心的形态。

串行调用与客户端仍负责的部分

串行调用在 Puppeteer 和 Playwright 集成中很常见,因为每个调用都会先被等待,下一个才开始。这对点击和其他离散动作是有用的完成约定。但对于一条较长的悬停路径,每个坐标之后都等待,意味着浏览器很少能同时收到几个靠得很近的普通移动。

开启上下文选项后,客户端可以保持其串行命令风格。调用方不需要生成第二条路径,不需要加入随机延迟,也不需要从页面内注入指针事件。现有的坐标和现有的控制流程仍是交互的来源,并且每个 CDP 命令保持其正常的完成约定。

这个改变针对的是投递,而不是轨迹质量。稀疏的路径仍然稀疏,带有突然跳变的路径仍然包含该跳变。如果页面需要特定的目标序列,应单独改进客户端的坐标和时序,再用部署将使用的选项设置来验证结果。

同样的区分也适用于应用逻辑。只在停留一段时间后才打开的工具提示仍然需要停留,要求指针穿过特定区域的菜单仍然需要该区域出现在路径中。合并有助于悬停移动以有序分组到达;它不能替代应用本身的交互规则。

会把一次移动插值成多个中间坐标的客户端库,例如 Playwright 和 Puppeteer 中 mouse.move 的 steps 选项,天然适合这种用法。每个中间坐标都是客户端已经选好的纯悬停移动,并且每一个仍然作为独立调用被等待。插值仍是客户端的工作;该选项只影响所得移动的投递方式。

用悬停步骤到达控件,再用正常的点击步骤去激活它,不要指望悬停分组来承载按钮状态转换。对于拖放,让完整的拖拽序列保持正常路径,并单独验证放置结果。

这种分离让失败更容易解读。工具提示没有出现时,检查悬停路径、目标几何位置和页面状态。点击没有激活控件时,检查焦点、命中测试和点击序列。拖拽没有完成时,检查拖拽源、目的地和应用的接受规则。一个设置不应变成解释所有指针问题的万能理由。

浏览器决定被投递的坐标如何变成页面事件。当浏览器调度合并了相近的移动时,页面可能看到一个主指针事件以及一组被合并的子事件,MDN 对 getCoalescedEvents 的参考文档对此有说明。事件数量会随调度、页面负载、主机负载和客户端数据流而变化,因此测试绝不应期望固定数量的页面事件。应测试可见结果、动作顺序、命令完成情况和最终指针位置。

用成对运行来验证

比较字段有界示例值验收用途
comparisonIdhover-menu-r17将两个上下文绑定到同一旅程
contextModeoff 或 on标出唯一变化的输入策略
viewport1440x900保持目标几何位置可比
coordinateRevisionpath-42标识有序悬停坐标列表
hoverStatemenu-visible记录所需页面结果
finalPointx=612,y=184确认到达预期目标
followupResultdestination-loaded将点击结果与悬停投递分开

使用一个小页面或经批准的测试路由,其中带有工具提示、悬停菜单或悬停卡片,并且在指针到达目标后会出现可见的状态变化。然后在两个独立的上下文中把同一段旅程各运行一次:

  1. 创建一个关闭该选项的上下文,或显式设为 false。
  2. 使用同一个客户端和同样的坐标走完目标路径。
  3. 记录悬停状态是否出现,以及最终指针位置是否到达目标。
  4. 创建另一个开启该选项的独立上下文。
  5. 重复同一路径,并记录同样的可见结果。

保持浏览器版本、profile、视口、页面状态、客户端包和坐标列表不变,每次只改变一个变量。页面事件的精确数量不是稳定的验收标准,因为事件调度由浏览器控制。

对于生产流程,在悬停状态出现后增加一次点击,并验证由此产生的页面状态。再加入一个不依赖悬停的控件,例如表单字段或普通按钮,以确认整条旅程仍然走正常的输入路径。只有在工作负载确实使用拖拽、滚轮、触摸或触控笔输入时,才加入相应的检查。

成功意味着所需的悬停状态可达,动作顺序正确,每个命令都得到一次完成,并且最终坐标没有丢失。它并不意味着每次运行都会暴露相同的合并列表或相同的页面事件数量。

针对一个获批的桌面审查流程,运行策略可以很简短:

  • 检查悬停菜单的上下文在其第一个页面之前开启 --bot-cdp-coalesce。
  • 测试点击、表单、键盘导航或拖放的上下文保持关闭,除非同一次运行也有已记录的悬停需求。
  • 共享的运行代码把该设置与浏览器版本和 profile 版本一起记录。
  • 流程先验证悬停结果,再把点击或拖拽结果作为单独的步骤来验证。
  • 替换上下文时,以显式设置和新的页面状态检查开始。

这样可以让该选项的使用范围保持狭窄,并防止共享启动模板变化时,测试套件悄悄改变自己的输入约定。显式的 false 值在同时服务两类上下文的模板中很有用。

当结果将用于部署决策时,请让没有编写该旅程的人审阅这次比较。第二位读者可以确认记录中的可见状态确实是应用所要求的,也可以确认没有任何步骤依赖特定数量的页面事件。与共享启动模板已经扩散到所有上下文之后再去排查相比,这种审阅的成本很低。

为每次比较保存一份简洁的运行记录。包含浏览器版本、profile 标识、视口、客户端库版本、上下文设置、页面路由、坐标列表修订版本以及运行时间。不要包含工作流不需要的账号内容和页面数据。记录明确写出上下文策略,以便用相同浏览器、profile、视口和坐标修订版本复现比较。

从相同的起始页面状态出发,把开启该选项的上下文与另一个关闭该选项的独立上下文进行比较。记下目标是否变得可见、指针是否到达预期的最终坐标、后续动作是否生效,以及每个 CDP 命令是否只完成了一次。对于悬停菜单,记录点击前的菜单状态和点击后的目的地。对于工具提示,把它的出现和消失记录为旅程的一部分。

把每次比较限定在一对浏览器与 profile 上。当浏览器版本、profile、视口、客户端包或页面修订版本发生变化时,应建立新的基线,而不是把旧结果当作直接可比的对象。事件数量只作为辅助信息,当悬停状态变得不可达、动作顺序改变、某个命令没有完成,或最终坐标错误时,再升级处理该比较。

如果客户端库在可见的悬停状态出现之前就报告命令完成,请等待你真正需要的页面状态。CDP 命令完成与应用就绪是两个独立的条件,所以应使用应用的可见信号、受支持的页面断言,或属于该流程的有限就绪等待。

选项没有可见效果。 确认上下文在第一个页面之前收到了该 flag,确认移动是纯鼠标悬停移动,并确认页面确实会对悬停做出反应。点击、拖拽、滚轮、触摸、触控笔或相对移动序列不在该选项的范围内。

开启选项后拖拽的行为发生了变化。 把悬停接近和拖拽序列分开,并通过正常路径开始拖拽。该选项不承载活动中的拖拽移动。

不同运行之间事件数量发生了变化。 当调度或页面负载不同时,这是预期之内的。请改为比较可达的悬停状态、动作顺序、命令完成情况和最终坐标。

两个上下文的表现不同。 检查每个上下文的显式值、浏览器版本与 profile、视口、页面状态以及客户端的坐标列表。该设置按上下文隔离,不会修复这些其他输入上的差异。

页面仍然感觉很慢。 合并无法修复稀疏的路径、沉重的页面、缓慢的选择器或应用的停留要求。请在页面层面衡量这段旅程,再调整相关步骤,而不要改动不相关的输入类型。

BotBrowser 的适用范围

BotBrowser 的 --bot-cdp-coalesce 是单个 BrowserContext 的可选设置:它在 Chromium 投递之前按顺序分组短序列的纯 CDP 鼠标悬停移动。它不改写按钮、拖拽、滚轮、键盘、触摸、触控笔或相对移动;这些输入保留各自的标准投递路径。该选项也不能补全稀疏坐标、替代应用停留规则、修复页面就绪问题,或保证固定的页面事件数量,因为最终调度仍由浏览器控制。

BotBrowser 支持在获授权的 BrowserContext 中运行同一条悬停旅程并比较 contextMode=off 与 contextMode=on 的可见结果;它不能生成缺失坐标、改变应用交互规则,也不能证明业务操作已经完成。

该选项不会改变浏览器身份设置、网络路由、cookie、存储、权限、视口配置或 profile 数据,因为这些仍在各自的配置入口中。相关实践可参阅 浏览器与 profile 变更后的交互验证(基线比较)、指针事件与无障碍输入(页面如何对待鼠标、触摸和触控笔),以及 BrowserContext 容量规划(在一个浏览器中运行多个上下文)。

--bot-cdp-coalesce 为部署提供了一个针对狭窄交互类别的明确选择。默认值仍是关闭。只为发送密集纯鼠标悬停移动的上下文开启它,让其他输入类型保持标准路径,验证可见结果,并把该值与上下文配置的其余内容一起记录。

实践结论

只为有文档记录的悬停旅程开启 --bot-cdp-coalesce,在创建第一个页面前应用,并且只有在成对比较中所需的可见状态和后续动作都通过时才接受变更。BotBrowser 负责符合条件的悬停移动投递;路径仍由客户端负责,旅程是否正确由应用负责人决定。

来源

#CDP#鼠标输入#浏览器上下文#交互一致性#隐私

本文属于指南: 浏览器自动化入门:首次运行地图

让 BotBrowser 从研究走向生产

先用这些指南理解模型,再进入跨平台验证、隔离上下文和面向规模化的浏览器部署。