Files
cv-cat dc078b248b catbus:一个命令操作小红书、抖音、TikTok、B 站、快手、微博、闲鱼、淘宝、京东、X
10 个平台的 web 端全部用 TypeScript 移植自 cv-cat 的开源项目,请求与上游逐字节对拍。
统一的命令语法与 JSON 输出、按 平台 × 端 × 账号 隔离的登录态、给 AI Agent 用的技能与 llms.txt。
2026-10-06 19:24:55 +08:00

181 lines
8.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 输出与错误处理
catbus 的输出同时面向人和程序(脚本、Agent):**stdout 只输出 JSON**,日志、提示、进度、二维码一律在 stderr。唯一的例外是 `--help`,它把帮助文字写到 stdout。
规范见 [AGENTS.md 第 6 节](../../AGENTS.md#6-输出)。
## 信封
默认 `-o json` 时,stdout 恰好输出一个信封,成功和失败都是:
```json
{
"ok": true,
"platform": "bilibili",
"endpoint": "web",
"resource": "item",
"action": "search",
"account": "default",
"data": [ { "id": "BV1...", "kind": "video", "...": "..." } ],
"page": { "cursor": "2", "has_more": true },
"error": null
}
```
| 字段 | 说明 |
|---|---|
| `ok` | 是否成功 |
| `platform` / `endpoint` / `resource` / `action` | 执行的命令,平台用规范 id(别名也会归一成规范 id) |
| `account` | 使用的账号名 |
| `data` | 结果:单个对象、数组,失败时为 null |
| `page` | 分页命令为 `{cursor, has_more}`,其他命令为 null |
| `error` | 失败时为 `{code, message, hint, detail}`,成功时为 null |
- stdout 是终端时缩进输出,重定向到文件或管道时输出紧凑的一行。
- 全局命令(`platforms`、`doctor`、`auth list`、`config`、`version`)的 `platform`、`endpoint`、`account` 为 null,`resource` 是命令名,`action` 是子命令(没有时为 null)。
## json 与 jsonl
`-o jsonl` 时 stdout 每行一个 `data` 条目:
- 列表命令一行一条,翻页时边翻边输出,适合大批量导出;
- 非列表命令只有一行;
- 结束时在 **stderr** 写一行摘要信封,`data` 为 null,带 `page` 和 `error`,用来取下一页游标或错误信息。
```bash
catbus xhs user items <user-url> --all -o jsonl > items.jsonl 2> run.log
tail -n 1 run.log | jq '{ok, page, error}'
```
`live listen`、`msg listen` 这类长连接命令总是输出 jsonl(一行一个事件),直到 Ctrl-C 或 `--duration` 到期,退出码 0。
## --raw
归一化会丢掉平台私有字段。需要原始数据时加 `--raw`:每个归一化对象换成平台返回的原始对象,信封结构不变。
```bash
catbus bilibili item get BV1xx411c7mD --raw | jq '.data | keys'
```
原始对象的结构随平台和接口变化,不保证稳定;写脚本时优先用归一化字段。
## 归一化类型
同一种对象在所有平台上结构相同。常用类型:
| 类型 | 字段 |
|---|---|
| UserRef | `id name url` |
| User | `id name handle avatar url bio stats{followers following items likes}` |
| Item | `id kind url title text author:UserRef created_at cover media:Media[] stats{views likes comments collects shares} price:Price\|null status\|null` |
| Media | `id type url width height duration` |
| Price | `amount currency`(`amount` 以元等主单位计) |
| Comment | `id item_id parent_id author:UserRef text created_at stats{likes replies}` |
| Live | `id url title status host:UserRef cover stats{viewers}` |
| Event | `type time user:UserRef text gift{name count}\|null` |
| Conversation | `id peer:UserRef unread last_message updated_at` |
| Message | `id conversation_id from:UserRef type text media:Media[] created_at` |
| Notice | `id type user:UserRef target{id url}\|null text created_at` |
| AuthStatus | `logged_in user:UserRef\|null method expires_at` |
| Account | `platform endpoint account current user:UserRef\|null method updated_at` |
| File | `path type url size` |
完整的类型(Folder、Category、Keyword、Topic、Poi、Gift、Rank、Subtitle、Danmaku、Order、Coupon……)、枚举值和每条命令的输出类型见 [AGENTS.md 6.2](../../AGENTS.md#62-归一化类型)、[6.3](../../AGENTS.md#63-各命令的输出)。每条命令的输出类型也写在 `--help` 的「输出」一行里。
约定:
- ID 一律是字符串(包括 64 位整数 ID,不会丢精度)。
- 计数是整数或 null,「1.2万」会换算成 12000。
- 时间是带时区的 ISO 8601。
- 字段总是存在,取不到时为 null 或 `[]`。有些字段因为上游接口不返回而恒为 null,例如抖音作品的 `title`、抖音和小红书列表的 `stats.views`,各平台说明的「已知限制」里有完整列表。
- 所有对象都带 `id` 和 `url`,可以直接作为下一条命令的参数。
写操作的返回:成对动作(`like/unlike` 等)、`delete`、`live send` 等返回 `{id}`(目标对象的 id);`item publish` 返回 Item;`comment add` 返回 Comment;`msg send` 返回 Message;`item download` 返回 File[]。
## 分页与游标
列表命令默认只取一页:
| 选项 | 说明 |
|---|---|
| (不加) | 只取一页 |
| `--limit N` | 自动翻页,直到取满 N 条 |
| `--cursor <c>` | 从上次返回的 `page.cursor` 继续 |
| `--all` | 一直翻到没有更多 |
- 游标是**不透明字符串**,原样传回即可,不要自己解析或构造。各平台的游标格式不同(页码、offset、时间戳、base64……)。
- `--limit` 截在一页中间时,返回的游标会带 `#skip=N` 后缀:续翻时 catbus 会重取这一页、跳过已输出的 N 条,剩下的不会丢。
- `has_more` 为 false 时已经到底。服务端返回和上次相同的游标时,catbus 会停止翻页并在 stderr 警告,`--all` 不会死循环。
- 翻页间隔用平台的默认值,不需要自己加 sleep。
分批导出、断点续翻:
```bash
cursor=""
while :; do
out=$(catbus bilibili user items <user> --limit 100 ${cursor:+--cursor "$cursor"})
echo "$out" | jq -c '.data[]' >> items.jsonl
[ "$(echo "$out" | jq -r '.page.has_more')" = "true" ] || break
cursor=$(echo "$out" | jq -r '.page.cursor')
sleep 60
done
```
## 退出码
| 退出码 | code | 含义 | 建议 |
|---|---|---|---|
| 0 | — | 成功 | |
| 1 | `ERROR` | 未分类错误 | 看 `message`;可以带 `-v` 重跑看调试日志 |
| 2 | `USAGE` | 参数或选项错误 | 看 `hint` 和 `--help` |
| 2 | `UNSUPPORTED` | 平台 / 端没有这个命令,或不支持这个取值 | `hint` 会给出规范词、可选值或 `-e <端>` |
| 2 | `CONFIRM_REQUIRED` | 危险操作未确认 | 非交互环境加 `-y` |
| 3 | `AUTH_REQUIRED` | 未登录、账号不存在,或平台返回登录墙 | 执行 `hint` 里的登录命令 |
| 3 | `AUTH_EXPIRED` | 登录态失效 | 重新登录 |
| 4 | `NOT_IMPLEMENTED` | 规划中的能力(矩阵里的 ○)或端(app / pc) | 目前不支持,不必重试 |
| 5 | `RISK_CONTROL` | 验证码或风控,`detail.kind` 为 `captcha` / `rate_limit` / `blocked` | 停一停,不要连续重试,见 [faq.md](faq.md#遇到-risk_control-怎么办) |
| 6 | `NETWORK` | 网络 / 代理错误 | 检查网络和代理设置 |
| 7 | `UPSTREAM` | 平台返回业务错误 | 原始错误码在 `detail` 里 |
命令无法执行时的判断顺序:参数和选项先校验(写错的先报 `USAGE`);然后是规划中的端或能力(`NOT_IMPLEMENTED`);平台没有的概念或不在词表里的命令报 `UNSUPPORTED`。用了平台原生叫法(如 `note`、`video`)时,`hint` 会给出规范词:
```json
{"ok":false,"platform":"xhs","endpoint":"web","resource":"note","action":"get","account":null,"data":null,"page":null,
"error":{"code":"UNSUPPORTED","message":"xhs (web) 不支持 note get","hint":"用规范词:catbus xhs item get","detail":null}}
```
## 在脚本里处理错误
按退出码分支:
```bash
out=$(catbus xhs item get "$url")
case $? in
0) echo "$out" | jq '.data.title' ;;
3) echo "需要登录:$(echo "$out" | jq -r '.error.hint')" >&2; exit 1 ;;
5) echo "被风控了,稍后再试" >&2; exit 1 ;;
*) echo "$out" | jq -r '.error | "\(.code): \(.message)"' >&2; exit 1 ;;
esac
```
只取需要的字段:
```bash
# 搜索结果转成 TSV
catbus bilibili item search 猫 --limit 50 | jq -r '.data[] | [.id, .title, .author.name, .stats.views] | @tsv'
# 失败时打印错误码和建议
catbus douyin item get "$url" | jq -r 'if .ok then .data.url else "\(.error.code) \(.error.hint // "")" end'
# jsonl 逐行处理
catbus xhs comment list "$url" --all -o jsonl | jq -r '.text'
# 列出某个平台已实现的命令
catbus platforms kuaishou | jq -r '.data.commands[] | select(.status=="implemented") | "\(.resource) \(.action)"'
```
## 日志与提示
- `-v` 在 stderr 输出调试日志,cookie、token、Authorization、密码等字段已打码。贴到 issue 之前请再检查一遍。
- `-q` 只保留错误,不输出提示和进度。
- 提示、警告以 `[catbus]` 开头,不会混进 stdout。