跳到正文
郭立 (leeguoo)

桌面应用其实是网页:想通这点,操作它就不再是"桌面自动化"

第一次用 chrome-use 连上 Slack 桌面版、snapshot 出一堆带名字的按钮时我愣了一下,后来想通了——Slack 桌面版本来就是个网页。Electron 应用是 Chromium 渲染引擎套了层原生壳,内部有一棵结构清晰的 DOM。这篇讲为什么这件事让"桌面自动化"这个一直很脏的活退化成了操作网页,以及和浏览器场景相比一个必须知道的取舍。

本页目录

第一次用 chrome-use 连上 Slack 桌面版、snapshot 出来一堆带名字的按钮时,我愣了一下:这跟操作一个网页没任何区别。后来想通了,因为 Slack 桌面版本来就是个网页。

Electron 应用是一个 Chromium 渲染引擎加一层 Node.js 外壳。你以为在用"桌面软件"的 Slack、VS Code、Discord、Figma、Notion,它们的界面全是 Chromium 渲染出来的 HTML,只是外面套了个原生窗口的壳。这个事实一旦接受,一件本来很难的事就塌方式变简单:操作桌面应用,退化成了操作网页。

Slack/VS Code 等 Electron 应用外壳掀开,里面其实是 Chromium 网页;chrome-use 通过 CDP 远程调试口连上,按钮用 @e1/@e2 元素引用定位而非截图点坐标

桌面自动化本来有多别扭

先说没有这条路的时候,让程序操作一个桌面应用有多难。

一条路是截图、找按钮的像素坐标、点过去。分辨率一变、主题一换、窗口一挪,坐标全错;而且程序"看不懂"界面上是什么,它只看到一张图。另一条路是系统辅助功能 API(macOS 的 Accessibility、Windows 的 UIAutomation),能拿到控件树,但每个平台一套 API,而且 Electron 应用暴露给这套 API 的信息还经常残缺,因为它的"控件"其实是 div,不是原生控件。

两条路都累,而且都绕开了一个事实:这个应用内部明明有一棵结构清晰、带语义的 DOM,你却在外面隔着像素、或者隔着一层转译,去够它。

Chromium 自带一扇门

因为渲染引擎是 Chromium,Electron 应用天然会说 Chrome DevTools Protocol。启动时带上 --remote-debugging-port,它就开一个 CDP 端口,把内部那棵 DOM 直接露出来:

bash
open -a "Slack" --args --remote-debugging-port=9222
chrome-use connect 9222
chrome-use snapshot -i

(每个应用分个不冲突的端口就行,全平台的启动命令文档站有,这里不铺开。)

snapshot 拿回来的,是那棵 DOM 的无障碍视图:每个按钮、输入框都是带名字的元素,用 @ref 定位。你不是在猜"发送按钮大概在右下角那块像素",你拿到的是那个 button "Send" 本身。窗口挪了、主题换了都不影响,因为绑的是元素,不是坐标。对 agent 来说这差别是本质的:它现在能读懂这个桌面应用长什么样,而不是对着一张截图瞎点。

一个必须知道的取舍

这里有个和浏览器场景不一样的地方,值得单独说,因为很容易想当然。

操作你日常那个 Chrome 时,chrome-use 走的是浏览器扩展加 native messaging,不碰调试端口,所以没有"是否允许远程调试"的弹窗,也没有 Runtime.enable 那类协议层痕迹。但 Electron 应用装不了 Chrome 应用商店的扩展,所以这条路只能走 --remote-debugging-port。换句话说,浏览器场景下那些"零痕迹"的优势,到 Electron 这儿是拿不到的,前提就是你自己开一个调试端口连进去。

对自动化 Slack、VS Code 这种"你自己的应用"来说,这完全不是问题:你不是要骗过谁,是要自动化你自己已经登录的工具。但如果脑子里装着浏览器那套"不可检测"的预期跑来操作 Electron,得先把预期调过来:这是"连进自己的应用",不是"隐身操作别人的网站"。

一个有意思的细节:应用里还能套应用

Electron 应用内部经常再嵌 <webview>,比如 Slack 里打开的某个第三方应用面板,本质是又一个独立网页。这些在 CDP 里是独立的 target。连上后先 chrome-use tab 列一下,你会看到主窗口、设置窗口、还有那些 webview 各自是一个 target,可以分别切进去操作。

所以一个 Electron 应用不是"一个网页",是"一叠网页套在一个原生壳里"。想清楚这点,多窗口、嵌套面板这些本来挠头的场景,就都变成了"切到对的那个 target"而已。

边界

这套只对 Chromium 内核的应用成立。用 Swift/AppKit 写的纯原生应用没有 CDP 口,连不上,那种还得回到系统辅助功能,或者换别的工具(操作 iPhone 上的原生 app 我用的是另一套)。判断也简单:Slack、VS Code、Discord、Figma、Notion、Spotify 这类"一套代码跑多平台"的桌面应用,基本都是 Electron。

想通"桌面应用其实是网页"之后,我现在看到一个桌面工具,第一反应是先确认它是不是 Electron。是的话,操作它就不再是"桌面自动化"这个我一直觉得很脏的活,而是我已经很熟的那套开网页的办法。

相关文档:chrome-use · Electron 桌面应用、安装。

同分类的更多文章 · AI & Agent

2026年7月2日
3 分钟阅读
一个真实 Chrome,几个 agent,还有你自己:怎么不互相点乱
chrome-use 的卖点是让 agent 用你这一个真实浏览器,但这自带一个开新浏览器的工具没有的麻烦:好几个 agent 加上你本人同时在同一个 Chrome 里动手。这篇讲它怎么按"谁开的标签"来隔离(彩色标签组 + 专属 daemon + 只碰自己的页),以及一个不写出来会栽的取舍:这套隔离只在扩展连接路径成立,裸 --cdp 端口不隔离。
→
2026年7月2日
4 分钟阅读
反爬检测数的是你说了几次谎:真实浏览器为什么天生没破绽
做浏览器自动化的人迟早会掉进一个坑:拼命把假浏览器伪装成真人,再被一层层识破。想明白这件事,得先知道 CreepJS 这类检测压根不直接判断"你是不是机器人",它在收集你几十项信号做交叉核对,对不上一处记一条谎。这篇从我实测的一组真实指纹讲起,拆到最难盖的那条痕迹(在协议层,不在 JS 层),说清为什么打补丁是负和游戏。
→
2026年7月2日
3 分钟阅读
给 agent 取网页数据,我试过三种笨办法,最后只留下一种
塞整页 HTML 烧上下文、一个字段一次 find/get 往返、手搓 eval,这三种取数办法我都试过,都别扭。留下的是 chrome-use 的 site 和 extract,背后是同一个判断:取数该是一次声明式求值,不是一串命令式往返。这篇从真实输出讲清两者怎么用、extract 的 schema 到底怎么写(我一开始就写错过),以及它取不到、不该用的地方。
→
← 上一篇
反爬检测数的是你说了几次谎:真实浏览器为什么天生没破绽
下一篇 →
给 agent 选浏览器:Playwright 那套和 chrome-use 不是一回事

评论

评论发布后会立即公开,如触发规则可能被审核下架。

最多 1000 字。