如何让AI自动化操作你的HTML页面——WebSocket嵌入法


如何让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)  │                   └─────────────────┘
└──────────────┘

三部曲:

  1. HTML页面启动时,创建一个WebSocket Server监听本地端口(如9876)
  2. controller.js 通过原生TCP建立WebSocket连接,发送JSON命令
  3. 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:

  1. 怎么打开你的页面(Start-Process 还是直接用路径?)
  2. 要等多久(WebSocket启动时间)
  3. 每一步调用哪个 controller.js 命令
  4. 怎么验证结果
  5. 出错怎么办

步骤四:测试

在终端里把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的地图工具)设计的。当时遇到了几个痛点:

  1. agent-browser依赖太重:换台电脑要先装agent-browser,用户体验差
  2. PowerShell脚本太脆弱:路径编码、输出截断、中文乱码,踩了无数坑
  3. 截图方案不稳定:html2canvas对CSS3 transform支持有偏差

最终确定"页面内嵌WebSocket → controller.js发命令 → SKILL.md指挥AI"这条路线后,系统稳定下来了。现在这个技能文件夹拷贝到任何Windows电脑,AI都能稳定地帮用户做完一整套"填坐标→导出SHP→截图"的流程。

如果你也用HTML做了工具类页面,想让AI能操作它,这条路可能是成本最低、最稳定的一条。


欢迎在评论区交流你的浏览器自动化方案。


文章作者: 摸鱼
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 摸鱼 !
  目录