关于 reversing-network
这项技能将浏览器捕获的 API 流量转化为 Robomotion HTTP 流程,面向构建自动化的开发者,涵盖请求分析、认证与分页。
主要功能
- 01通过 Browser MCP 捕获 API 调用
- 02检查请求与响应详情
- 03使用 Robomotion SDK 构建 HTTP 流程
- 04处理 API 分页
- 05规划令牌与速率限制
适用场景
- 01用 API 请求替代浏览器交互
- 02复现网站登录与数据流程
- 03抓取分页 API 结果
MCP 相关
使用 `robomotion-browser-mcp` 捕获网络流量,再将分析结果用于 Robomotion 流程。
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ robomotionio/ agent-skills --skill reversing-network安装后在 Claude Code 中输入/reversing-network确认已加载。
附带文件config.json
详细介绍
逆向分析网络请求(浏览器 → HTTP)
通过 robomotion-browser-mcp 捕获网络流量,逆向分析底层 API,以更快速、更可靠的 HTTP 请求取代浏览器自动化。
配合使用: exploring-browser — 在探索时于该工具中捕获流量,然后回到这里进行转换。
何时使用
| 使用浏览器自动化 | 使用网络逆向分析 |
|---|---|
| 网站大量依赖 JS 渲染 | 网站数据来自 API 调用 |
| 没有明确的 API 端点 | 可通过 DevTools 找到 API 端点 |
| 登录需要执行 JS | 登录会在响应头或响应正文中返回令牌 |
| 网站选择器经常变化 | API 稳定且有版本管理 |
步骤 1:使用 Browser MCP 捕获网络流量
启用网络捕获后打开浏览器,然后执行目标操作:
1. browser_open(stealth: true)
2. browser_start_network_capture(url_filter: "api.", capture_body: true)
3. browser_navigate(url: "https://example.com/search")
4. browser_snapshot() — read the page to find interactive elements
5. browser_click / browser_type — perform the user action (search, login, etc.)
6. browser_get_requests(method: "POST") — list captured API calls
7. browser_get_request_response(request_id: "...") — inspect a specific pair
在操作之间使用 browser_snapshot() 查看页面状态。重复点击、输入和快照操作,直到目标 API 调用出现在 browser_get_requests 中。
步骤 2:分析捕获的请求
检查 browser_get_request_response 返回的 JSON,查看:
- 请求:
request.method、request.url、request.headers、request.body - 响应:
response.status、response.headers、response.body、response.mimeType
识别:
- 端点 URL — 通常包含版本号(
/api/v2/products) - 必需的请求头 — Authorization、X-API-Key、cookies、Content-Type
- 请求正文格式 — JSON、form-data、GraphQL
- 身份验证流程 — 登录是否会返回 Bearer 令牌?
步骤 3:构建 HTTP 工作流
import { flow, Message, Custom, Credential } from '@robomotion/sdk';
const myFlow = flow.create('main', 'API Scraper', (f) => {
f.node('start', 'Core.Trigger.Inject', 'Start', {})
// Step 1: Authenticate (if needed)
.then('auth', 'Core.Net.HttpRequest', 'Login', {
optUrl: Custom('https://api.example.com/auth/login'),
optMethod: 'post',
inBody: Custom(JSON.stringify({ username: '...', password: '...' })),
inCustomHeaders: [{ scope: 'Custom', name: { name: 'Content-Type', value: 'application/json' } }],
outBody: Message('auth_body'),
outStatus: Message('auth_status')
})
// Step 2: Extract token from response
.then('token', 'Core.Programming.Function', 'Extract Token', {
func: `
msg.bearer_token = 'Bearer ' + msg.auth_body.token;
return msg;
`
})
// Step 3: Build headers object with token
.then('headers', 'Core.Programming.Function', 'Build Headers', {
func: `
msg.headers = {
'Authorization': msg.bearer_token,
'Content-Type': 'application/json',
'User-Agent': 'Mozilla/5.0'
};
return msg;
`
})
// Step 4: Call the actual data API
.then('api', 'Core.Net.HttpRequest', 'Get Data', {
optUrl: Custom('https://api.example.com/products?page=1'),
optMethod: 'get',
inHeaders: Message('headers'),
outBody: Message('api_body'),
outStatus: Message('api_status')
})
// Step 5: Parse and process
.then('parse', 'Core.Programming.Function', 'Parse Response', {
func: `
msg.products = msg.api_body.items;
return msg;
`
})
.then('stop', 'Core.Flow.Stop', 'Done', {});
});
myFlow.start();
步骤 4:处理分页
对于分页 API,请使用循环模式:
// ForEach over page numbers or use cursor/offset from response
f.node('loop', 'Core.Programming.ForEach', 'Each Page', {
optInput: Message('page_numbers'), // [1, 2, 3, ...]
optOutput: Message('page_num')
})
// ... make API call with page_num ...
f.node('goto', 'Core.Flow.GoTo', 'Next', {
optNodes: { ids: ['LABEL_ID'], type: 'goto', all: false }
})
关键规则
- 在构建完整工作流之前,务必验证 API 响应格式
- 将凭据存储在保险库中 — 切勿将 API 密钥或令牌硬编码
- 处理速率限制 — 对于 429 响应,添加
delayBefore或重试循环 - 检查令牌是否过期 — 某些令牌会过期;如有需要,请添加刷新逻辑
- Core.Net.HttpRequest 是内置工具 — 无需额外依赖(它包含在
Core包中)
常见 HTTP 节点属性
使用 robomotion describe node Core.Net.HttpRequest 确认准确名称:
| 属性 | 值 |
|---|---|
| URL(选项) | optUrl: Custom('https://...') 或 Message('url') |
| 方法(选项) | optMethod: 'get' | 'post' | 'put' | 'delete' | 'patch'(小写枚举) |
| 请求头(输入) | inHeaders: Message('headers')(键值对象)或 inCustomHeaders: [{ scope: 'Custom', name: { name: 'X', value: 'Y' } }] |
| 正文(输入) | inBody: Custom(JSON.stringify({...})) 或 Message('body') |
| 响应正文(输出) | outBody: Message('resp_body') — 当 Content-Type: application/json 时为已解析的 JSON,否则为字符串 |
| 响应状态(输出) | outStatus: Message('status') |
| 响应头(输出) | outHeaders: Message('resp_headers') |
清理
完成捕获后,务必调用 browser_stop_network_capture 和 browser_close,即使构建工作流失败也不例外。让浏览器保持打开会浪费资源,还可能阻碍后续运行。
评论
支持 Markdown