Canvas 桌面自动化:华为云实验沙箱里的坐标折算与图像定位

举报
yd_243549746 发表于 2026/11/13 09:24:51 2026/11/13
【摘要】 在华为云学堂的云实验沙箱里做自动化,最难的不是点哪个按钮,而是根本没有按钮。实验桌面是用 canvas 渲染的远程桌面画面,DOM 里只有一块画布,没有图标、没有窗口、没有开始菜单。所有基于选择器的经验到这里全部失效。这篇记录我在 Linux 云桌面(Xfce)和 Windows 云桌面(DevEco Studio)两类沙箱里摸索出的定位方法,以及几个只在 canvas 场景才会踩到的坑。 ...

在华为云学堂的云实验沙箱里做自动化,最难的不是点哪个按钮,而是根本没有按钮。实验桌面是用 canvas 渲染的远程桌面画面,DOM 里只有一块画布,没有图标、没有窗口、没有开始菜单。所有基于选择器的经验到这里全部失效。

这篇记录我在 Linux 云桌面(Xfce)和 Windows 云桌面(DevEco Studio)两类沙箱里摸索出的定位方法,以及几个只在 canvas 场景才会踩到的坑。

一、先确认"没有 DOM",别浪费时间找选择器

进入实验沙箱后,右侧默认只显示拓扑示意图。必须点顶部工具栏的第一个图标才能切出云桌面——这一步本身就是易错点:第二个图标是剪贴板,长得也像屏幕,点错会打开一个空的剪贴板面板。

切过去之后可以验证一下:

document.querySelectorAll('canvas').length   // 1
document.querySelectorAll('button').length   // 工具栏那几个,桌面里一个都没有

桌面区域只有一块 canvas。此时无论用 getByRole('button') 还是 XPath 找"DevEco Studio",都不可能命中——图标是画上去的像素,不是元素。判断标准很简单:如果在快照里看不到桌面上的任何应用名,就不要再用选择器思路了。

二、截图是唯一可靠的"眼睛"

拿到画布的原始像素有两种方式,差别很大:

const buf = await page.locator('canvas').first().screenshot();

这是元素截图,返回的是图片,尺寸按设备像素比放大。也可以用 toDataURL() 直接读 canvas 内部缓冲,但远程桌面通常是 WebGL 或分块绘制的,toDataURL 有可能拿到空白图——尤其是画面还在刷新的时候。所以元素截图更稳。

关键在于:截图的像素尺寸和 CSS 视口尺寸不是一回事。实测中画布 CSS 尺寸是 959×619,而截图宽度是 1080,比例约 1.126。如果不做折算,直接拿截图上的坐标去点鼠标,误差会随距离线性放大——在左上角还能点中,到右下角就偏出几十像素,正好落在两个图标之间。

折算公式:

cssX = cssWidth  / imgWidth  * imgX
cssY = cssHeight / imgHeight * imgY

更省事的做法是先把截图缩放到 CSS 尺寸再读坐标,人眼在图上量的位置就能直接用。

三、必须用真实鼠标事件

canvas 不监听 DOM 的 click。你在 canvas 上派发一个 MouseEvent,浏览器会正常触发事件,但远程桌面协议收不到任何输入——因为画面上的点击是由 VNC/RDP 通道传输的,只认真实的指针事件序列。

所以:

  • element.click() 无效
  • dispatchEvent(new MouseEvent('click')) 无效
  • 只有 page.mouse.click(x, y) / page.mouse.dblclick(x, y) 有效

双击还有额外要求。page.mouse.dblclick 内部会连续发两次 down/up,但两次点击的间隔、以及是否带 clickCount,都影响远端识别。我遇到过"双击被识别成两次单击"的情况:图标被选中了两次,程序没启动。后来改成手动控制节奏就稳定了:

await page.mouse.move(x, y);
await page.mouse.down(); await page.mouse.up();
await page.waitForTimeout(80);
await page.mouse.down(); await page.mouse.up();

80 毫秒这个间隔不是拍脑袋——低于 40ms 容易合并成一次,高于 250ms 会被当成两次独立单击。这个区间在不同沙箱镜像上略有差异,换镜像要重新试。

四、等待不能靠 sleep,要靠像素

远程桌面的加载时间波动极大:同一台机器,冷启动要 10 秒,热启动 3 秒就到位;IDE 从双击到出现 Welcome 页,实测 60 到 90 秒不等。

固定 waitForTimeout(90000) 的问题是双重的:短了会点空,长了纯浪费。更麻烦的是点空之后没有任何报错——鼠标点在一块还没画出来的区域,什么都不会发生,脚本继续往下走,最后在某个不相关的步骤超时,排查方向完全错了。

可行的做法是小步轮询 + 局部像素判断:

  1. 每 3 秒截一次图,只截目标区域的小矩形(比如桌面中央 300×200),避免全图编码开销
  2. 判断这块区域是否"有内容"——平均亮度高于阈值、或者与上一帧的差异超过某个比例
  3. 连续两帧稳定(差异小于 1%)再认为加载完成

这套逻辑不需要图像识别库,纯靠像素统计就够用。如果一定要做模板匹配,记住先把模板和目标缩放到同一比例,否则永远匹配不上。

五、什么时候该放弃

云实验沙箱有个特点:它对"失败"的容忍度很低,而且不给你明确的失败信号。连不上、画面卡住、权限框反复弹出,页面上都不会报错,只会静静地停在那里。

我给自己定的规则是"三次原则":

  • 进入沙箱失败 3 次 → 放弃,记录现象
  • IDE 启动超时 3 次 → 放弃
  • 同一个弹窗关掉又弹 3 次 → 放弃

理由很实际:沙箱按时长计费(哪怕是 0 实验点的免费实验,也占着今天的免费名额),在一个已经确定起不来的环境里反复重试,除了耗时间没有任何收益。而且这类失败往往和环境镜像、区域负载有关,脚本层面改不出来。

六、别忘了收尾

做完操作要点"结束实验",弹窗确认后环境会被回收,标签页通常会自动关闭——这时候 waitForTimeout 会抛 Target closed,属于正常现象,不要当成错误去重试。

如果没点结束就走人,环境会挂到超时自动清理,期间占着名额。这一点在自动化里特别容易被忽略:脚本"跑完了"和"实验结束了"是两件事。

小结

canvas 桌面的自动化,本质上是从"操作 DOM"退化成"操作像素"。三个转换必须做对:像素坐标到 CSS 坐标的折算、真实鼠标事件替代 DOM 事件、像素轮询替代时间等待。剩下的是工程纪律——知道什么时候该停。

这套方法不限于华为云沙箱,任何基于 noVNC / RDP 网关的网页远程桌面都适用。真正的难点从来不是技术本身,而是接受"这里没有选择器可用"这个前提,然后老老实实去看图。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。