在 WSL(Windows Subsystem for Linux)中实现可视化浏览器自动化,经历了从失败到成功的完整过程,记录如下。
目标
在 Hermes Agent 中,通过可视化的浏览器操作来控制 WordPress 网站 mottobook.com,即用户能亲眼看到浏览器窗口在桌面上打开、输入、点击的全过程,而不是通过 API 或 Headless 模式在后台悄悄完成。
第一次尝试:连接 Windows Chrome CDP
最初的思路是:WSL 中运行的 Hermes Agent 通过 Chrome DevTools Protocol(CDP)连接到 Windows 上已经打开的 Chrome 浏览器,用 Puppeteer 远程控制。
具体做法是在 Windows Chrome 的快捷方式中添加 --remote-debugging-port=9222 参数启动,然后在 WSL 中通过 http://127.0.0.1:9222 连接。
失败原因
WSL 默认网络模式是 NAT。WSL 2 虚拟机有自己的虚拟网卡(通常是 172.x.x.x 网段),与 Windows 宿主机不在同一个网络命名空间中。虽然 localhostForwarding 默认开启,但 CDP 连接需要稳定的双向通信,NAT 模式下 127.0.0.1:9222 无法从 WSL 访问 Windows 端口。
解决办法是在 C:\Users\<用户名>\.wslconfig 中配置:
[wsl2]
networkingMode=mirrored
localhostForwarding=true
networkingMode=mirrored 能让 WSL 2 的 IP 地址与 Windows 宿主机的 IP 地址一致,127.0.0.1 完全互通。配置后需要执行 wsl --shutdown 重启 WSL。
然而,重启后 mirrored 模式仍未生效(WSL 仍是 NAT 模式的 172.x.x.x IP)。这是因为 Windows 10 对 mirrored networking 的支持有限,且 .wslconfig 加载可能存在缓存问题。反复尝试均未成功。
第二次尝试(成功):WSL 内安装 Chrome + WSLg 图形显示
放弃连接 Windows Chrome 的方案,改为在 WSL 内部安装 Google Chrome Linux 版,利用 WSLg(Windows Subsystem for Linux GUI)将图形界面直接投射到 Windows 桌面上。
步骤
- 安装 Google Chrome:从 dl.google.com 下载
google-chrome-stable_current_amd64.deb(124MB),用dpkg -i和apt-get install -f安装依赖。 - 安装 Puppeteer:
npm install puppeteer --save,跳过浏览器下载(PUPPETEER_SKIP_DOWNLOAD=true),指定使用系统已安装的 Chrome。 - 安装中文字体:
apt install fonts-noto-cjk fonts-wqy-zenhei fonts-wqy-microhei,确保网页中文显示正常。 - 启动可视化浏览器:Puppeteer 启动参数加上
headless: false,浏览器窗口自动出现在 Windows 桌面。
遇到的问题
首次运行时,网页内容中文正常,但 Chrome 窗口标题栏(显示页面标题和关闭按钮的那一行)中文显示为乱码。原因是:
- Chrome 默认通过 XWayland 运行
- WSLg 的 Weston 合成器(Wayland compositor)负责绘制 X11 窗口的标题栏装饰
- Weston 使用的 Pango/Cairo 字体栈找不到中文字体,导致标题栏乱码
解决办法:启用 Chrome Wayland 原生模式。
在启动参数中添加:
--ozone-platform=wayland
--enable-features=WaylandWindowDecorations
这样 Chrome 使用 Wayland 协议直接与 WSLg 通信,并采用客户端侧装饰(CSD, Client-Side Decorations)——即 Chrome 自己绘制标题栏、关闭/最小化/最大化按钮,使用自己的字体引擎渲染文字。由于 Chrome 的网页渲染引擎(Blink/Skia)已能正确显示中文,由它绘制的标题栏自然也不再乱码。
与之前的可视化操作有什么区别
之前在这台机器上也成功实现过可视化浏览器操作,但那是通过 Puppeteer 直接控制 Windows 上的 Chrome(通过 CDP 连接)。那次是在 Windows 原生环境中运行 Node.js + Puppeteer,WSL 只是作为控制端发送指令。
这次的方案完全不同:
| 维度 | 之前(Windows Chrome CDP) | 现在(WSL 内部 Chrome + WSLg) |
|---|---|---|
| 浏览器位置 | Windows 原生 Chrome | WSL 内安装的 Linux Chrome |
| 图形显示方式 | Windows 原生桌面 | WSLg → Wayland → RDP → Windows 桌面 |
| 连接方式 | CDP 远程调试协议(网络连接) | Puppeteer 本地驱动(进程间通信) |
| 标题栏渲染 | Windows DWM(Desktop Window Manager) | Chrome 自身 CSD(Client-Side Decorations) |
| 中文支持 | Windows 字体系统,天然支持 | 需安装 Linux 中文字体 + Wayland 模式 |
| 网络要求 | 需 WSL 与 Windows 网络互通(mirrored 模式) | 无需网络互通,全部在 WSL 内部完成 |
| 稳定性 | 依赖 Windows Chrome 的开启状态 | 完全由 WSL 控制,自启动自管理 |
总结
WSLg 是 WSL 中运行 GUI 应用的关键基础设施。虽然默认的 XWayland 兼容模式在标题栏字体渲染上存在短板,但通过 Chrome 的原生 Wayland 模式(Ozone Platform)可以绕过这个问题。这套方案不依赖 Windows 端的任何配置,完全在 WSL 内部闭环运行,更适合自动化场景。

