dsh-web-recorder
语言:简体中文 · English

网页操作录制器插件:面向「用户手动操作浏览器,插件在后台录制」的场景。它可以 attach 到已打开的浏览器窗口(如带调试端口的 Playwright MCP 浏览器,这个是可选的),也可以自己启动一个有头浏览器窗口(默认本机 Edge);用户在窗口里正常点网页,插件在后台记录每次点击 / 输入 / 表单提交和每个网络请求 / 响应 / 失败,停止后生成 Markdown 摘要报告。
设计初衷
要让 agent 直接通过接口对接某个业务平台(例如 EIP 类系统),前提是先搞清楚三件事:平台暴露了哪些接口、每个业务步骤对应调用哪个、参数和响应是什么格式。传统做法是查接口文档或逆向前端代码,但文档往往缺失或过时,而且就算有了接口清单,也很难把「用户在页面上的业务操作」和「背后触发的接口调用」一一对上。
本插件换一种思路:不逆向,只留操作依据。开发者先让记录仪就位(recorder_start),再让目标业务流程在一个受监控的有头浏览器窗口里完整跑一遍即可——操作可以由真人手动完成,也可以交给 playwright MCP / browser-use 等浏览器自动化工具按步骤驱动——之后不需要再翻文档,因为这次操作留下的原始数据已经回答了上面三个问题:
- UI 事件线:每一步点击 / 输入 / 表单提交发生在何时、落在哪个元素、填了什么值;
- 网络事件线:每一步操作触发了哪些
xhr/fetch请求——method、URL、请求头、请求体、响应体、失败原因。
两类事件按时间交错实时写入 events.jsonl,两条线天然对齐:任何一个业务步骤,都能在原始数据里找到「它调了哪个接口、参数怎么填、返回了什么」。停止后生成的 report.md 再把这套操作时间线与请求明细整理成便于阅读的摘要。
得到这些原始依据后,交给大模型做分析:归纳出完整的「业务流程 × 接口调用序列 × 数据契约」,再沉淀为 skill——把流程拆成步骤,注明每步该调哪个接口、请求 / 响应长什么样、出错怎么办——让 agent 之后照着 skill 直接走接口完成任务,整个过程不再依赖人工演示。
一句话概括:页面操作一遍 = 留下可分析的操作依据 = 大模型据此制作接口级 skill 的原料。录制本身只是采集,分析和沉淀交给模型完成。
效果预览
下面是一次真实录制的产物截图(tests/smoke.mjs 冒烟测试在一个本地页面执行「输入关键词 → 查询 → 去第二页」的完整流程)。
① report.md 摘要——统计概览 + 操作时间线 + 网络请求明细,把「业务步骤」和「接口调用」整理在同一张表里:

② events.jsonl 原始事件流——每一行一个事件(导航 / 点击 / 输入 / 请求 / 响应…),按发生时间交错实时落盘,是分析时最完整的操作依据:

两张图对照着看:一次「输入关键词并查询」的操作,在 events.jsonl 里留下了对应的 POST /api/query 请求与 200 响应事件,在 report.md 里则汇总成一行请求明细——这正是设计初衷里「页面操作一遍,留下可分析的操作依据」的直观体现。
🚀 安装
前置:已装好 DSH(dsh web 能正常运行),Node.js ≥ 18、pnpm ≥ 8。
dsh plugin --profile web add dsh-web-recorder@latest
装完硬刷新浏览器(Cmd/Ctrl+Shift+R)即可在 DSH 会话工具列表里看到 recorder_* 工具(DSH 对 client 改动热加载,无需重启;仅 host 半更新时需要重启)。
让 DSH 自己装——把下面这段提示词发给任意一个 DSH 会话:
帮我安装 dsh-web-recorder 插件(网页操作录制器),步骤:
1. 执行 dsh plugin --profile web add dsh-web-recorder@latest
2. 完成后提醒我硬刷新浏览器(Cmd/Ctrl+Shift+R)
更新dsh plugin --profile web add dsh-web-recorder@latest
更新完硬刷新浏览器(Cmd/Ctrl+Shift+R)即可生效。
常见问题| 现象 | 原因与解决 |
|---|---|
报 Ignored build scripts |
pnpm 拦截了构建脚本。在 profile 目录(~/.dsh/profiles/web)跑 pnpm approve-builds --all。 |
| 报「找不到 profile 目录」 | 先跑一次 dsh web,让它初始化 ~/.dsh/profiles/web。 |
提示 dsh: command not found |
先安装 DSH;或直接用 npx -y --package @deepseek-ai/dsh dsh plugin --profile web add dsh-web-recorder@latest。 |
调试本地改动时,把依赖指向本地克隆并自行构建:
1. git clone https://github.com/kakajun/dsh-web-recorder.git ~/Code/dsh-web-recorder
cd ~/Code/dsh-web-recorder && pnpm install && pnpm build
2. ~/.dsh/profiles/web/package.json 的 dependencies 写 "dsh-web-recorder": "link:<克隆目录绝对路径>"
3. 在 ~/.dsh/profiles/web 执行 pnpm install
4. 硬刷新浏览器(Cmd/Ctrl+Shift+R)即可生效
更新:git pull && pnpm install && pnpm build → 硬刷新浏览器即可。
注册的工具
| 工具 | 说明 |
|---|---|
recorder_start(url?, waitSeconds?) |
开始录制:优先 attach 到已有浏览器窗口(cdpUrl / 自动发现带调试端口的 Playwright MCP 浏览器),否则启动有头浏览器并可导航到起始 URL;waitSeconds 可让录制先等 N 秒再记录(跳过登录 / 初始化);事件实时落盘 events.jsonl |
recorder_stop() |
停止录制:生成 report.md 摘要报告;attach 模式只断开 CDP 连接,插件自启的窗口才关闭;幂等 |
recorder_status() |
查询状态:是否在录制、事件分类计数、产物目录、上一次收尾结果 |
用户直接关掉浏览器窗口会自动收尾(reason: browser-closed),已录数据不丢。
使用方法:如何命中本插件
什么时候会命中(触发场景)
插件的 3 个工具会随插件启用出现在 DSH 会话的工具列表里,「命中」发生在模型做工具选择时——依据是工具名与描述。当用户任务属于「查清某个网页业务流程背后调用了哪些接口、参数/响应长什么样,并据此生成接口级流程说明或 skill」时,模型应主动调用 recorder_*。这类任务通常要分步完成:先打开目标页面开始录制,再由驱动方(真人或自动化工具)在页面上完成实际操作,最后基于录制结果分析沉淀。典型任务表述:
- "帮我打开
http://目标地址,开始录制" - "打开 XX 页面,我操作一遍,你录下来再分析接口调用"
- "我在页面上点『查询』时发了什么请求?帮我录下来看看"
- "打开
http://目标地址,先等我 30 秒,然后再开始录"
如果只是回答不涉及真实页面操作的问题(例如直接查文档就能答),模型通常不会命中本插件。
工具如何可用(加载)
本仓库即 DSH 插件:入口 lib/index.js(源码 src/index.ts),经 package.json 的 dsh.bundle.patch 指向仓库根 cordis.patch.yml 并入宿主 profile(其中 id/name 均为 dsh-web-recorder);@deepseek-ai/* 由宿主按 peerDependencies 提供。插件启用后工具即进入模型工具列表,无需额外声明即可被选择。
职责划分:本插件只「记录」,「打开页面 / 操作」交给驱动方
本插件不直接操作页面——工具只有 recorder_start / recorder_stop / recorder_status,职责是「旁观并记录」:它启动一个受监控的有头浏览器窗口,把窗口里发生的每一步 UI 操作与每个网络请求原样落盘。真正「打开 XXXX 页面并按步骤操作」的是浏览器驱动方,可以是:
- 真人:在插件弹出的窗口里手动点击 / 输入 / 跳转;
- playwright MCP(可选):模型通过它打开页面、点击、填表,把目标流程一步步执行出来;
- 其他 browser-use 类工具(可选):同样作为"手"来驱动浏览器执行流程。
playwright MCP 不是必需依赖:没有装它、没有 browser-use,插件照样能录——真人在弹出的窗口里手动操作一遍即可,这也是最省事的方式。MCP / browser-use 的价值只在于把「打开页面 + 按步骤操作」自动化,属于可选项。
模型(agent)在会话里做编排:先让记录仪就位,再指挥驱动方执行流程,最后收尾并读取产物分析。
推荐流程:打开 X 页面 → 录制步骤(有 / 没有 playwright MCP 都适用)
- (可选,有 MCP 时推荐)驱动方先把页面打开:让 playwright MCP 打开目标页面;只要 MCP 浏览器以
--remote-debugging-port启动(见下文「协同前提」),recorder_start会自动发现它的 CDP 端口并 attach 到这个已打开的窗口,无需新开浏览器,MCP 也能继续在这个窗口上操作。没有 playwright MCP 就跳过本步,直接进第 2 步,由真人在插件弹出的窗口里操作 - 记录仪就位:
recorder_start()——attach 到已有窗口,或弹出受监控浏览器并打开起始页,从此刻起窗口内一切操作与网络请求都开始实时落盘events.jsonl(注意:从这一刻起发生的页面加载也会被录进来,见下文「初始化请求噪音」) - 驱动方执行流程:让 playwright MCP / browser-use(或真人)在同一个受监控窗口里逐步完成目标流程——打开各页面、填写表单、点击提交、翻页……每步操作的 UI 事件和它触发的接口调用都会被同时录下
- (可选)查进度:
recorder_status()——查看是否在录制、事件分类计数、产物目录 - 收尾:
recorder_stop()——生成report.md摘要报告(attach 模式只断开 CDP 连接,不关闭外部浏览器;插件自启的窗口会关闭;用户直接关窗口也会自动收尾) - 分析沉淀:模型读取
report.md+events.jsonl,归纳「流程步骤 × 接口调用 × 请求/响应契约」,进一步沉淀为 skill 或接口对接文档
协同前提(重要)
- playwright MCP 是可选的,不是前置依赖:没装它、也没装 browser-use,插件照样能录——真人在插件弹出的窗口里手动操作一遍即可(这也是最常见的用法)。MCP / browser-use 只是把「打开页面 + 按步骤操作」自动化的可选项。
- 唯一「不能在 playwright MCP 已打开的浏览器上继续操作」的场景:MCP 的浏览器没有带
--remote-debugging-port。此时录制器无法 attach 上去,只能走「接管」回退——记下 MCP 浏览器当前页面 URL 后把 MCP 浏览器进程关掉,再用插件自启窗口打开同一页面;此后 MCP 与原来那个浏览器的连接已经断了,无法再驱动它(MCP 若重新开一个窗口,那个新窗口同样不在录制范围内)。想让 MCP 与录制器共存、MCP 继续在受录制的窗口里操作,就必须给 MCP 浏览器加调试端口(或用显式cdpUrl指向它)。 - 录制范围是插件 attach / 启动的那个浏览器窗口(含其新标签页与 iframe);驱动方(真人或自动化工具)的操作必须发生在这个窗口里才会被录到。
- 与 playwright MCP 共用同一个浏览器窗口:让 MCP 启动浏览器时带上远程调试端口,记录仪即可自动 attach。给
@playwright/mcp传一个配置文件(--config=path/to/playwright-mcp.config.json),内容为:
端口为{ "browser": { "launchOptions": { "args": ["--remote-debugging-port=0"] } } }0时 Chrome 自动挑选空闲端口并写入其 user-data-dir 下的DevToolsActivePort文件,recorder_start会自动读取并完成 attach(Windows 上通过进程命令行里的ms-playwright-mcpuser-data-dir 定位)。未配置调试端口时记录仪无法 attach,会回退到接管模式:记录 MCP 浏览器当前页面 URL 后关闭它,再用插件自启窗口打开同一页面。 - 也可以在插件 Config 中显式设置
cdpUrl(如http://127.0.0.1:9222)指定 attach 目标,优先级高于自动发现;此时recorder_stop只会断开 CDP 连接,不会关闭外部浏览器进程。
前置条件与注意
- 本机需装有浏览器:默认用 Edge(
channel: msedge),可配chrome或executablePath;插件不下载浏览器 - 不强制要求 playwright MCP:驱动方可以是真人(在插件弹出的窗口里操作),也可以是 playwright MCP / browser-use 等自动化工具;两者都没有时,插件自己打开窗口,由真人操作即可
- 配置
cdpUrl或 MCP 浏览器带--remote-debugging-port时,记录仪优先通过 Chrome DevTools Protocol attach 到已有浏览器实例;attach 失败会回退到接管/新开窗口 - CDP attach 模式下,
recorder_stop不会关闭外部浏览器进程,仅断开录制连接;普通模式(未 attach)下结束会关闭插件自启的窗口 events.jsonl含请求头/请求体/响应体等完整数据,按敏感数据处理,勿外发
初始化请求噪音:直接打开页面会多录一批接口(已实测确认)
录制从 recorder_start 那一刻开始,凡是开始之后发生的页面加载,其请求都在录制范围内。所以 recorder_start(url) 直接打开页面(或录制开始后再由驱动方导航)时,页面自身的初始化请求会被完整录进来——登录态校验、字典/枚举、菜单、配置、用户信息、埋点上报等等。
实测(本地页面加载时发 2 个初始化接口 /api/init、/api/config,点击按钮才发业务接口 /api/query):
| 方式 | 初始化接口事件 | 业务接口事件 |
|---|---|---|
recorder_start(url) 直接打开页面 |
2(/api/init + /api/config) |
点击后同样会录到 |
| 页面先加载完成再 attach 录制 | 0 | 1(/api/query) |
差异来自「页面加载发生在录制开始之前还是之后」,与页面本身无关。
影响:这些初始化接口通常与目标业务流程无关,会稀释有效信息——尤其分析「点『查询』发了什么请求」时,需要额外分辨哪些是页面固有的、哪些是操作触发的。
怎么减少这类噪音:
- 首选 attach 模式:让驱动方(playwright MCP 带
--remote-debugging-port,或显式cdpUrl)先把目标页面打开、等它加载稳定,再recorder_start()(不传 url)——录制从「页面已就绪」开始,初始化接口不计入。 - 需要登录/跳转才能到达目标页时:起录时直接传
waitSeconds(见下一节),让插件先等 N 秒再开始记录;已经录了的话,按时间把开头的加载段裁掉。 - 录完后剔除:
events.jsonl里紧跟在navigate事件之后、且没有对应 UI 事件(click / change / submit)的请求,基本都是初始化噪音。 - 取基线:操作前先
recorder_status()记下eventCount,之后只看seq大于该基线的事件,即可跳过开头那批加载请求。 - 分析时以操作时间线为准:
report.md把 UI 事件与请求按时间交错列出,能对应上某次点击/输入的请求才是真正的业务流程接口。
等待期:recorder_start 的 waitSeconds(起录即跳过登录 / 初始化)
对「目标站要登录」或「首页加载会刷一堆初始化接口」的场景,不用事后裁剪——起录时直接让插件先等一会儿:
recorder_start({ url: "https://目标地址/login", waitSeconds: 10 })
- 语义只有一个:开始录制后先等 10 秒再开始记录,等价于「把前 10 秒从录制结果里剔除」。等待期内发生的点击 / 输入 / 导航 / 请求一律不落盘,等待期结束后才正常记录。
- 计时起点:
recorder_start被调用的时刻。浏览器启动与起始页导航都算在这段时间里,所以「登录 → 跳首页 → 首页初始化」这一整段都在被跳过的范围内。 - 整组丢弃:请求若发起于等待期内,它的响应 / 失败也一并丢弃,不会出现「只有响应没有请求」的半条记录。
- 可观测:
recorder_status()的waitRemainingSec告诉你还要等多久才开始记录(> 0 时此刻的操作不会被记录),skippedEvents是等待期内已丢弃的事件数;recorder_stop()的结果与report.md头部同样会写「等待 10s 后开始记录: 等待期内 N 个事件已丢弃」。 - 不传或传 0 = 立即开始记录(默认,与旧行为一致)。
录制内容
- UI 事件:点击(选择器 + 元素文本 + 坐标)、输入/选择变更(name + 值,密码框只记录动作不落值)、表单提交、页面导航。通过
context.exposeBinding+addInitScript捕获阶段监听实现,覆盖新标签页与 iframe。 - 网络事件:默认只录
xhr/fetch接口调用(requestResourceTypes可调)——每个请求的 method/URL/resourceType/请求头/请求体,响应的状态码与响应体(截断),失败请求的错误原因。可选记录 console 消息。 - 产物:每次录制在
<outputDir>/rec-<时间戳>/下生成events.jsonl(完整数据,逐行实时写入)和report.md(操作时间线 + 请求明细表 + 失败请求摘要)。
Config 字段
| 字段 | 默认值 | 说明 |
|---|---|---|
channel |
msedge |
playwright-core 浏览器渠道(msedge/chrome),使用本机已装浏览器,不下载 Chromium |
executablePath |
'' |
自定义浏览器可执行文件路径,非空时覆盖 channel |
cdpUrl |
'' |
CDP 调试地址(如 http://127.0.0.1:9222),非空时优先 attach 到已有浏览器;留空时自动发现带 CDP 端口的 Playwright MCP 浏览器;都失败则回退到接管/新开窗口 |
outputDir |
'' |
产物输出根目录;空则默认当前工作目录(用户正在操作的文件夹,harness 会话 cwd)下 reports/recorder |
captureResponseBodies |
true |
是否抓取 xhr/fetch 响应体 |
maxBodyBytes |
16384 |
单个请求体/响应体最大记录字节数,超出截断 |
recordConsole |
false |
是否记录 console 消息 |
requestResourceTypes |
xhr,fetch |
逗号分隔的 resourceType 白名单,只有命中的请求才录制(响应/失败事件随请求一并过滤);默认只录接口调用,静态资源/文档不录 |
redactHeaders |
cookie,authorization,proxy-authorization,x-api-key,set-cookie |
逗号分隔的脱敏请求头名(大小写不敏感),命中头值记为 <redacted> |
构建与验证
pnpm install # 安装依赖(devDependencies 与 peerDependencies 对齐)
pnpm typecheck # tsc --noEmit
pnpm test # vitest 单元测试(report 生成纯函数)
pnpm build # tsdown 产物到 lib/(插件加载与 smoke 依赖产物)
pnpm smoke # 真实 Edge 端到端冒烟(需本机已装浏览器, 产物在 reports/)
pnpm smoke:cdp # CDP attach 模式端到端冒烟(需本机已装浏览器, 产物在 reports/)
pnpm smoke:mcp # MCP 浏览器自动发现 attach 冒烟(模拟带调试端口的 MCP Chrome)
pnpm smoke:wait # 等待期(前置剔除)冒烟: 验证 waitSeconds 等待期内不记录、等待期后正常记录
仓库收录清单(awesome-dsh-plugin)
本仓库已按 awesome-dsh-plugin/contributing 对齐:
package.json声明dsh.bundle.patch: ./cordis.patch.yml(见仓库根cordis.patch.yml, 其中 id 与插件内部注册名dsh-web-recorder一致)- 官方
@deepseek-ai/*包放在peerDependencies:dsh-tools的范围带显式预发布分支(harness 以 rc 版本发布, 无分支的宽范围会被 node-semver 静默排除),cordis/schemastery同为 peer 由宿主提供 - 运行时默认产物输出到**当前工作目录(用户正在操作的文件夹)**下
reports/recorder,可用Config.outputDir显式指定 - 附带真实冒烟测试
tests/smoke.mjs, 非占位仓库
若提交 awesome-dsh-plugin 收录条目:
- 在 GitHub 仓库 Settings → Topics 添加
dsh-plugin - 一句话描述与代码实际能力一致、不夸大(例如称"3 个工具"就必须真有 3 个)
- 可选: 发布 npm(须保证
repository指回本仓库, 并去掉private: true); 可选在仓库根放screenshots.json
已知限制
- 只录制插件 attach / 自己启动的浏览器窗口(含其新标签页 / iframe),无法录制其他浏览器实例里的操作。要让 playwright MCP / browser-use 等自动化工具的操作被录到,需让它们驱动与记录仪相同的浏览器实例:MCP 以
--remote-debugging-port启动时记录仪会自动 CDP attach(见「协同前提」),未开启调试端口的 MCP 浏览器只能走接管回退(关掉 MCP 浏览器、开插件自启窗口,此后 MCP 无法再驱动原来那个窗口)。 - playwright MCP / browser-use 都不是必需依赖(真人操作即可),但接管回退模式下 MCP 浏览器会被关闭,之后只能由真人在插件自启窗口里继续操作。
- 插件自启窗口模式下,起始页的加载必然发生在录制开始之后,因此会连带录进一批页面初始化请求(登录态/字典/配置/埋点等),见「初始化请求噪音」一节;只有 attach 到「已加载完成」的页面才能避开。
- 请求头中的敏感头默认脱敏;请求体/响应体不做内容级脱敏(可能含 token 等业务数据),
events.jsonl应按敏感数据处理,不要外发。 - 跨域 iframe 的 UI 事件依赖 init script 注入,极少数强 CSP 页面可能注入失败(网络事件不受影响)。
- 点击接口请求后立即跳转页面时,浏览器会取消该响应体的抓取,此场景响应体可能缺失(事件仍在,只是无 body)。
No comments yet. Be the first to write one.