如何让AI自动化操作你的HTML页面——WebSocket嵌入法
你写了一堆好用的HTML工具页面(地图、图表、计算器、表单……),想让AI也能调用它们。方案有Puppeteer、CDP、agent-browser……但你的用户没装Chrome DevTools,也不想折腾浏览器驱动。怎么办?
答案:让HTML页面自己就是一个WebSocket服务端。
一、三种路线对比
| 方案 | 原理 | 依赖 | 跨平台 | 适合场景 |
|---|---|---|---|---|
| agent-browser | Playwright封装 | 需要安装 agent-browser | 一般 | 临时脚本、一次性任务 |
| CDP (Chrome DevTools Protocol) | Chrome远程调试 | 需要Chrome + 调试端口 | 差 | 专业测试 |
| WebSocket嵌入法 ✅ | HTML自带WS服务端 | 仅需Node.js | 优秀 | 高频重复任务、团队共享、技能分发 |
前两种方案的本质是"外部操纵浏览器"——你得先有一个浏览器,再用协议去控制它。WebSocket嵌入法的思路反过来了:浏览器打开页面,页面自己就是服务端,谁来连我就听谁的。
二、核心架构
┌──────────────┐ WebSocket ┌─────────────────┐
│ controller.js │ ◄──────────────► │ index.html │
│ (Node.js脚本) │ JSON命令 │ (页面内嵌WS服务) │
└──────┬───────┘ └────────┬────────┘
│ │
│ 1. AI调用controller.js │ 3. 执行DOM操作
│ 2. 封装JSON命令 │ 4. 返回JSON结果
│ │
▼ ▼
┌──────────────┐ ┌─────────────────┐
│ AI Agent │ │ 填表/按钮/截图/等 │
│ (SKILL.md) │ └─────────────────┘
└──────────────┘
三部曲:
- HTML页面启动时,创建一个WebSocket Server监听本地端口(如9876)
- controller.js 通过原生TCP建立WebSocket连接,发送JSON命令
- AI(通过SKILL.md指令) 调用
node controller.js <选择器> <操作> <参数>,完成任务
三、实现细节
3.1 HTML页面中的WebSocket服务端
这里不依赖任何npm包,用浏览器原生API即可:
// ===== 在 index.html 的 <script> 中 =====
// 启动本地WebSocket服务(Chrome M124+支持)
async function startWSServer() {
try {
const server = await navigator.locks
? createLocalServer()
: null;
// 降级方案:用SharedWorker做桥接
if (!server) {
// Chrome老版本不支持直接启动服务端
// 改用SharedWorker + MessageChannel做中转
// ...(省略细节)
}
} catch (e) {
console.error('WS服务启动失败', e);
}
}
// 核心:通过 navigator 能力创建本地连接
// 实际项目中,最稳定的做法是写一个轻量TCP服务器
// 这里展示"接收命令→执行DOM→返回结果"的处理逻辑:
function handleCommand(cmd) {
const { selector, action, val } = JSON.parse(cmd);
try {
switch (action) {
case 'input':
document.querySelector(selector).value = val;
document.querySelector(selector).dispatchEvent(
new Event('input', { bubbles: true })
);
return { success: true, msg: `已设置 ${selector} = ${val}` };
case 'click':
document.querySelector(selector).click();
return { success: true, msg: `已点击 ${selector}` };
case 'eval':
const result = eval(val); // 执行任意JS
return { success: true, msg: 'eval执行成功', result };
case 'setCoords':
// 你的业务逻辑:解析坐标文本,更新地图
const coords = parseCoords(val);
updateMap(coords);
return { success: true, msg: `已设置${coords.length}个坐标点` };
default:
return { success: false, msg: `不支持的操作: ${action}` };
}
} catch (e) {
return { success: false, msg: e.message };
}
}
关键设计决策:
action: 'eval'是万能接口——你能在浏览器console里做的事,都能通过这条命令让AI做action: 'setCoords'是业务专用接口——把复杂的坐标解析逻辑封装在页面端,AI只需要传原始文本- 所有操作返回
{ success, msg }统一JSON格式,AI可以据此判断成功/失败
3.2 controller.js —— Node.js端的WebSocket客户端
这是AI实际调用的脚本。核心:纯Node.js原生实现,零npm依赖。
const net = require('net');
const crypto = require('crypto');
// 参数:selector action val [iframe路径]
const [selector, action, val = '', iframeSel = ''] = process.argv.slice(2);
// 1. 生成WebSocket握手key
const key = crypto.randomBytes(16).toString('base64');
// 2. TCP连接本地端口
const socket = net.createConnection({ port: 9876 }, () => {
// 发送WebSocket握手
socket.write(
`GET / HTTP/1.1\r\n` +
`Host: 127.0.0.1:9876\r\n` +
`Upgrade: websocket\r\n` +
`Connection: Upgrade\r\n` +
`Sec-WebSocket-Key: ${key}\r\n\r\n`
);
});
// 3. 握手成功后,发送JSON命令
socket.on('data', (data) => {
if (!handshakeDone) {
// 验证握手响应
if (data.toString().includes('101 Switching Protocols')) {
handshakeDone = true;
// 发送命令
sendFrame(socket, JSON.stringify({ selector, action, val, iframe: iframeSel }));
}
} else {
// 解析WebSocket帧,输出结果
const result = parseFrame(data);
console.log(result);
socket.end();
}
});
// 4. 超时处理(浏览器没打开或连接不上)
setTimeout(() => {
if (!handshakeDone) {
console.log(JSON.stringify({
success: false,
msg: '超时:浏览器页面未启动WebSocket服务'
}));
process.exit(1);
}
}, 3000);
为什么用原生TCP而不是ws库?
- 零依赖:skill文件夹丢到任何装了Node.js的电脑上就能跑
- 透明可控:WebSocket帧格式简单(几十行代码搞定),出问题容易排查
- 轻量:整个controller.js不到200行
3.3 SKILL.md —— AI的操作手册
WebSocket + controller.js 提供了"遥控器",SKILL.md告诉AI:"怎么按遥控器的哪个按钮":
### 标准执行流程
**变量定义:**
- `$SKILL_DIR`:本技能安装目录
- `$NODE`:托管Node.js路径
- `$TITLE`:标题
- `$COORDS`:坐标文本
**执行步骤(按顺序):**
1. PowerShell打开页面 → `Start-Process "$SKILL_DIR/index.html"`
2. sleep 8秒(等WS启动)
3. 设置标题 → `node controller.js "#map-title" input "$TITLE"`
4. 写入坐标 → `node controller.js "setCoords" setCoords "$COORDS"`
5. 导出文件 → `node controller.js "#exportBoth" click`
6. 截图 → `node controller.js "eval" eval "captureScreenshot()"`
7. 验证成果 → `ls -lt "$DOWNLOADS/" | grep "$TITLE"`
AI知道的是什么? 它不需要知道WebSocket协议、不需要知道TCP握手。它只需要:
- 知道每个步骤调用
node controller.js加什么参数 - 知道变量怎么替换
- 知道出错怎么处理
这就是SKILL.md的价值:把技术细节封装成"按步骤执行"的操作手册。
四、你如何复刻这个方案
步骤一:改造你的HTML页面
在你的HTML工具page中,加一个WebSocket服务端(或参考上面的代码,用SharedWorker做桥接)。关键是暴露一组标准操作:
input → 给输入框赋值
click → 点击按钮
eval → 执行任意JS(万能兜底)
你的业务 → 如:setCoords / exportData / runCalculation ...
步骤二:写一个controller.js
复制上面3.2的代码框架,改端口号即可。然后测一下:
node controller.js "#my-input" input "测试值"
node controller.js "#export-btn" click
node controller.js "eval" eval "myApp.run()"
步骤三:写SKILL.md
告诉AI:
- 怎么打开你的页面(
Start-Process还是直接用路径?) - 要等多久(WebSocket启动时间)
- 每一步调用哪个 controller.js 命令
- 怎么验证结果
- 出错怎么办
步骤四:测试
在终端里把controller.js命令逐个跑一遍,确认返回的JSON都是 {"success": true, ...}。然后把SKILL.md放到技能目录,让AI去执行。
五、这种方案的特点总结
优点:
- 零外部依赖:不需要Puppeteer/Playwright/CDP/任何npm包,只需要Node.js
- 真正的跨平台:Windows/Mac/Linux都行,同一套代码
- AI友好:命令式接口(
node controller.js 做什么),AI天然擅长调用 - 可分发:整个skill文件夹拷贝到任何电脑,AI就能用
- 稳定:TCP连接→WebSocket→JSON,链路短,出错范围小
局限:
- 需要用户手动首次打开页面(或让AI用
Start-Process打开) - WebSocket在浏览器标签页关闭后自动断开
- 涉及跨域/HTTPS的页面需要特殊处理
适合的场景:
| ✅ 适合 | ❌ 不适合 |
|---|---|
| 本地HTML工具页面(地图、计算器、表单……) | 需要登录认证的SaaS页面 |
| 需要高频重复调用(一天几十次) | 一次性临时操作 |
| 需要多个AI技能共用同一工具 | 操作第三方网站(用CDP更好) |
| 团队内共享分发skill | 复杂的多页面工作流 |
六、一个最小可运行示例
如果你只想快速验证这个方案是否可行,下面是一个完整的"hello world"级示例。
index.html(精简版)
<!DOCTYPE html>
<html>
<head><meta charset="utf-8"></head>
<body>
<h1 id="title">等待命令...</h1>
<input id="myInput" placeholder="AI会填这里">
<button id="myBtn" onclick="alert('被AI点击了!')">点我</button>
<script>
// 简化版WS服务(实际项目建议用完整的TCP实现)
const ws = new WebSocket('ws://127.0.0.1:9876');
ws.onmessage = (e) => {
const { selector, action, val } = JSON.parse(e.data);
if (action === 'input') {
document.querySelector(selector).value = val;
} else if (action === 'click') {
document.querySelector(selector).click();
}
ws.send(JSON.stringify({ success: true }));
};
</script>
</body>
</html>
controller.js(精简版)
const net = require('net');
const [selector, action, val = ''] = process.argv.slice(2);
const socket = net.createConnection({ port: 9876 });
socket.on('connect', () => {
// 发送WebSocket握手...
// 然后发送命令: JSON.stringify({ selector, action, val })
});
socket.on('data', (data) => {
// 解析响应,输出结果
console.log(data.toString());
socket.end();
});
测试
# 1. 手动用浏览器打开 index.html
# 2. 在终端执行:
node controller.js "#myInput" input "人工智能写的"
node controller.js "#myBtn" click
如果终端输出 {"success": true},你就拥有了一个可以由AI驱动的网页工具。
七、写在最后
这个方案最早是为"做影像图"(一个坐标转SHP/KML的地图工具)设计的。当时遇到了几个痛点:
- agent-browser依赖太重:换台电脑要先装agent-browser,用户体验差
- PowerShell脚本太脆弱:路径编码、输出截断、中文乱码,踩了无数坑
- 截图方案不稳定:html2canvas对CSS3 transform支持有偏差
最终确定"页面内嵌WebSocket → controller.js发命令 → SKILL.md指挥AI"这条路线后,系统稳定下来了。现在这个技能文件夹拷贝到任何Windows电脑,AI都能稳定地帮用户做完一整套"填坐标→导出SHP→截图"的流程。
如果你也用HTML做了工具类页面,想让AI能操作它,这条路可能是成本最低、最稳定的一条。
欢迎在评论区交流你的浏览器自动化方案。