在构建 AI Agent 自动化系统时,浏览器操作是最常见的需求之一:自动登录、填写表单、抓取数据、发布内容。传统方案如 Selenium、Playwright 虽然成熟,但在与现有 Agent 框架集成时往往显得笨重——需要额外安装驱动、管理浏览器实例、处理进程生命周期。
本文分享一种更轻量的方案:直接基于 Chrome DevTools Protocol (CDP) 实现浏览器自动化,并将其无缝嵌入 Agent 工作流。
Chrome DevTools Protocol 是 Chromium 内核暴露的一套远程调试接口。通过 WebSocket 连接,外部程序可以:
核心优势:无需驱动程序,直接操控已安装的浏览器实例。
我们的自动化系统分为三层:
Agent调度层(OpenClaw) -> 控制层(xbrowser CLI) -> 执行层(Edge/CDP)
# 关闭现有 Edge 进程
Get-Process msedge -ErrorAction SilentlyContinue | Stop-Process -Force
# 以调试模式启动
Start-Process "msedge.exe" `
-ArgumentList "--remote-debugging-port=9222", `
"--user-data-dir=C:\\EdgeDebugProfile", `
"--no-first-run", "--no-default-browser-check"const response = await fetch('http://localhost:9222/json/list');
const pages = await response.json();
// 找到目标页面
const targetPage = pages.find(p => p.url.includes('target-site.com'));
const wsUrl = targetPage.webSocketDebuggerUrl;const WebSocket = require('ws');
const ws = new WebSocket(wsUrl);
ws.on('open', () => {
// 启用 DOM 和网络监控
ws.send(JSON.stringify({ id: 1, method: 'DOM.enable' }));
ws.send(JSON.stringify({ id: 2, method: 'Network.enable' }));
});
// 执行点击操作
function clickElement(nodeId) {
ws.send(JSON.stringify({
id: 3,
method: 'DOM.querySelector',
params: { nodeId, selector: 'button#submit' }
}));
}完整流程伪代码:
async function publishArticle(title, content) {
// 1. 打开编辑器
await navigate('https://example.com/editor');
await waitForLoad('networkidle');
// 2. 填写标题
const titleInput = await querySelector('input[name="title"]');
await fill(titleInput, title);
// 3. 切换到 Markdown 模式(避免富文本格式问题)
const mdTab = await querySelector('.tab-markdown');
await click(mdTab);
// 4. 填写正文
const contentArea = await querySelector('textarea#content');
await fill(contentArea, content);
// 5. 保存草稿
const saveBtn = await querySelector('button[data-action="save-draft"]');
await click(saveBtn);
await waitForSelector('.toast-success');
// 6. 打开发布弹窗
const publishBtn = await querySelector('button[data-action="publish"]');
await click(publishBtn);
// 7. 填写发布选项
await click(await querySelector('input[name="original"]')); // 原创
await click(await querySelector('.tag-automation')); // 标签
// 8. 确认发布
await click(await querySelector('button.confirm-publish'));
return await waitForNavigation('/article/');
}问题:CDP 返回的 nodeId 是临时的,页面刷新或 DOM 重绘后失效。
解决:每次操作前重新执行 DOM.querySelector,不要缓存 nodeId。
问题:某些富文本编辑器基于 contenteditable,直接 DOM.setNodeValue 无法触发输入事件。
解决:使用 Input.insertText 模拟键盘输入,或切换到 Markdown 编辑器。
问题:发布弹窗可能是动态创建的,不在初始 DOM 中。
解决:监听 DOM.childNodeInserted 事件,等待弹窗出现后再操作。
ws.on('message', (data) => {
const msg = JSON.parse(data);
if (msg.method === 'DOM.childNodeInserted') {
if (msg.params.node.nodeName === 'DIV' &&
msg.params.node.attributes.class?.includes('publish-modal')) {
handlePublishModal();
}
}
});问题:调试模式启动的浏览器是独立实例,没有用户的登录 Cookie。
解决方案 A:在调试浏览器中手动登录一次,保存用户数据目录。
解决方案 B:使用用户日常浏览器的 Profile(需先关闭浏览器再启动调试模式)。
优化点 | 方案 |
|---|---|
超时控制 | 每个操作设置 30 秒超时,防止无限等待 |
重试机制 | 元素未找到时重试 3 次,间隔 1 秒 |
截图留痕 | 关键步骤后截图,便于排查问题 |
网络监控 | 监听 |
资源清理 | 任务结束后关闭 WebSocket、清理临时 Profile |
基于 CDP 的浏览器自动化方案,相比传统 Selenium/Playwright:
优势:
局限:
这套方案已稳定运行在我们的自动化发布系统中,日均处理数十篇内容发布任务。希望对你构建自己的 Agent 工作流有所启发。
参考链接:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。