# B站（bilibili）接口台账

> 唯一证据来源：`/tmp/aiddit_captures/bili_search.json`、`bili_detail.json`、`bili_video_dl.json`（2026-06-11 真实抓包）。
> 全部接口走统一爬虫网关 `host = http://crawler.aiddit.com`。
> 本文档字段表与示例值全部取自上述 capture 真实响应，未做任何编造。

## 平台级结论（先读）

- **关键词搜索可用**：`/crawler/bilibili/keyword` `code=0`，一次返回 42 条（`bili_search.json`），每条含 `author/uid(实为 mid)/mid/bvid/aid/tag/arcurl/play/favorites` 等。
- **详情可用**：`/crawler/bilibili/detail` `code=0`，返回归一化结构，含 `topic_list / video_url_list / channel_account_id`（`bili_detail.json`）。
- **视频可下载**：`video_url_list[].video_url`（`.m4s`）直接 GET 返回 `206 / application/octet-stream`，实测收到 1,048,576 字节真实视频字节（`bili_video_dl.json`）。**下载 m4s 需带 `Referer: https://www.bilibili.com/`**（B站防盗链）。
- **集合中无作者作品接口**：本批 capture 内 **没有** “按 mid/uid 拉某 up 主全部作品” 的接口。作者维度只能从 search 结果里的 `mid/author` 取标识，无法直接游走到该作者的作品列表。`author_to_works` 边在 B站当前缺乏数据源支撑。
- **tag 来源**：search 的 `tag`（逗号分隔字符串）+ detail 的 `topic_list`（数组）两处均可取 hashtag。

---

## 接口 1：关键词搜索

### ① 身份
- `source_id`: **PLT_BILIBILI_KEYWORD**
- 状态：**verified**（`bili_search.json` `code=0`，42 条）
- 系统：crawler.aiddit.com

### ② 请求标准
- method：`POST`
- path：`/crawler/bilibili/keyword`
- 鉴权：网关侧统一处理，请求体无 token（capture 中 `request_body` 仅含业务参数）。
- 参数表：

| 参数 | 类型 | 必填 | 含义 | 真实值 |
|---|---|---|---|---|
| `keyword` | string | 是 | 搜索词 | `"彩虹"` |
| `cursor` | string | 否 | 翻页游标，取上次响应的 `next_cursor`（页码语义，首页可省略） | 见 ④ |

### ③ 真实 curl
```bash
curl -X POST 'http://crawler.aiddit.com/crawler/bilibili/keyword' \
  -H 'Content-Type: application/json' \
  -d '{"keyword":"彩虹"}'
```

### ④ 响应信封 + 翻页
```json
{ "code": 0, "msg": null,
  "data": { "has_more": true, "next_cursor": "2", "data": [ {...}, ... 42 条 ] } }
```
- 信封：`code`（0=成功）/`msg`/`data`。
- 翻页：外层 `data.has_more=true`，`data.next_cursor="2"`（页码字符串）。下一页把 `next_cursor` 回填到请求 `cursor`。
- 列表在 `data.data`（数组，本次 42 条）。

### ⑤ 字段台账（raw 名，取自 `bili_search.json` `data.data[0]`）

| 字段名(raw) | 类型 | 含义 | 提取标注 | 真实示例值 |
|---|---|---|---|---|
| `bvid` | string | 内容ID（B站视频主键） | 直接可用 | `"BV1qd4y1x76w"` |
| `aid` | int | 内容ID（av号，旧主键） | 直接可用 | `390658123` |
| `title` | string | 标题（含 `<em class="keyword">` 高亮标签） | 需正则抽（剥 `<em>`） | `"《<em class=\"keyword\">彩虹</em>》TimeZ～..."` |
| `arcurl` | string | 内容网页地址 | 直接可用 | `"http://www.bilibili.com/video/av390658123"` |
| `pic` | string | 封面图（协议相对 `//`） | 需后处理（补 `https:`） | `"//i1.hdslb.com/bfs/archive/70c0...jpg"` |
| `description` / `desc` | string | 简介 | 直接可用 | `"作词: 宋秉洋\n作曲: 宋秉洋..."` |
| `author` | string | 作者昵称 | 直接可用 | `"碍音乐"` |
| `mid` | int | 作者ID（UP主 mid，真实标识） | 直接可用 | `1919171246` |
| `uid` | int | 作者ID字段（**本响应恒为 0，不可用**，以 `mid` 为准） | 需后处理（弃用，取 mid） | `0` |
| `upic` | string | 作者头像 | 直接可用 | `"https://i2.hdslb.com/bfs/face/...jpg"` |
| `tag` | string | hashtag（逗号分隔） | 需后处理（split `,`） | `"音乐分享官5.0,TimeZ,音乐分享官,彩虹"` |
| `play` | int | 播放数 | 直接可用 | `2602076` |
| `like` | int | 点赞数 | 直接可用 | `32770` |
| `favorites` | int | 收藏数 | 直接可用 | `74847` |
| `review` | int | 评论数 | 直接可用 | `1181` |
| `danmaku` / `video_review` | int | 弹幕数 | 直接可用 | `3521` |
| `duration` | string | 时长（`分:秒` 文本） | 需后处理（转秒） | `"3:58"` |
| `pubdate` / `senddate` | int | 发布时间戳（秒） | 需后处理（×1000） | `1669795676` |
| `typename` | string | 分区名 | 直接可用 | `"音乐综合"` |

> 翻页字段：`data.has_more=true` / `data.next_cursor="2"`（真值）。

### ⑥ 提取与后处理规则
- 内容主键统一取 `bvid`（canonical `platform_content_id`），`aid` 作辅助。
- `title` 必须正则剥离 `<em class="keyword">...</em>` 高亮标签。
- 作者ID取 `mid`（`uid` 恒为 0，**禁止使用**）。
- `tag` 按 `,` 切成数组 → hashtag。
- `pic`/`upic` 协议相对地址需补 `https:`。
- **B站集合中无作者作品接口**：拿到 `mid` 后无法在本批接口内拉该作者作品；`author_to_works` 在 B站不可走，作者维度仅作标识沉淀。

### ⑦ 边界与失败
- 限流：跨接口请求间隔 ≥ 15s。
- 本接口 capture `code=0` 正常，无失败样本。

### ⑧ 落点（canonical + 游走边）
- canonical：`platform_content_id`(=`bvid`)、`platform_author_id`(=`mid`)、`title`、`content_url`(=`arcurl`)、`cover_url`(=`pic`)、`author_name`(=`author`)、`tags`(=`tag` split)、`stats.play/like/favorites/review/danmaku`、`publish_ts`、`has_more`/`next_cursor`。
- 游走边：`search_page_to_content`（search→每条内容）。`video_to_author` 仅能落作者标识（mid/author），**`author_to_works` 无数据源、不可走**。`video_to_hashtag` 由 `tag` 提供。

---

## 接口 2：内容详情

### ① 身份
- `source_id`: **PLT_BILIBILI_CONTENT_DETAIL**
- 状态：**verified**（`bili_detail.json` `code=0`）

### ② 请求标准
- method：`POST`，path：`/crawler/bilibili/detail`
- 参数表：

| 参数 | 类型 | 必填 | 含义 | 真实值 |
|---|---|---|---|---|
| `content_id` | string | 是 | 内容ID，传 `bvid` | `"BV1qd4y1x76w"` |

### ③ 真实 curl
```bash
curl -X POST 'http://crawler.aiddit.com/crawler/bilibili/detail' \
  -H 'Content-Type: application/json' \
  -d '{"content_id":"BV1qd4y1x76w"}'
```

### ④ 响应信封 + 翻页
```json
{ "code": 0, "msg": null,
  "data": { "has_more": false, "next_cursor": null, "data": { ...归一化对象... } } }
```
- 详情为单对象，`has_more=false`、`next_cursor=null`（无翻页）。

### ⑤ 字段台账（raw 名，取自 `bili_detail.json` `data.data`）

| 字段名(raw) | 类型 | 含义 | 提取标注 | 真实示例值 |
|---|---|---|---|---|
| `channel_content_id` | string | 内容ID（=bvid） | 直接可用 | `"BV1qd4y1x76w"` |
| `content_link` | string | 内容网页地址 | 直接可用 | `"https://www.bilibili.com/video/BV1qd4y1x76w/"` |
| `title` | string | 标题（无高亮标签） | 直接可用 | `"《彩虹》TimeZ～在夕阳下最后的拥抱 记得你甜美的心跳"` |
| `body_text` | string | 正文/简介 | 直接可用 | `"作词: 宋秉洋\n作曲: 宋秉洋\n制作人: 司捷"` |
| `content_type` | string | 内容类型 | 直接可用 | `"video"` |
| `topic_list` | string[] | hashtag/话题数组 | 直接可用 | `["发现《彩虹》","音乐分享官","彩虹","TimeZ","音乐分享官5.0"]` |
| `video_url_list[].video_url` | string | **视频地址（m4s，可下载）** | 需二次请求下载（带 Referer） | `"https://xy115...bilivideo.cn:8082/.../907810383_nb3-1-30016.m4s?..."` |
| `video_url_list[].video_duration` | int | 视频时长（秒） | 直接可用 | `238` |
| `voice_data.play_url` | string | 音轨地址（m4s，与视频分轨） | 需二次请求下载 | `"https://xy111...bilivideo.cn:8082/.../907810383_nb3-1-30216.m4s?..."` |
| `image_url_list[].image_url` | string | 封面图 | 直接可用 | `"http://i1.hdslb.com/bfs/archive/70c0...jpg"` |
| `channel_account_id` | string | 作者ID（mid 字符串形态） | 直接可用 | `"1919171246"` |
| `channel_account_name` | string | 作者昵称 | 直接可用 | `"碍音乐"` |
| `play_count` | int | 播放数 | 直接可用 | `2602076` |
| `like_count` | int | 点赞数 | 直接可用 | `33628` |
| `collect_count` | int | 收藏数 | 直接可用 | `74847` |
| `comment_count` | int | 评论数 | 直接可用 | `1181` |
| `share_count` | int | 分享数 | 直接可用 | `5367` |
| `publish_timestamp` | int | 发布时间戳（毫秒） | 直接可用 | `1669795676000` |

### ⑥ 提取与后处理规则
- `channel_account_id` 与 search 的 `mid` 一致（`"1919171246"`），可作作者主键对齐。
- B站视频/音频分轨（DASH）：`video_url_list` 为视频轨，`voice_data.play_url` 为音频轨，**需各自下载后合并**。
- **B站集合中无作者作品接口**：详情拿到 `channel_account_id` 后同样无法拉作者作品。

### ⑦ 边界与失败
- m4s 地址带 `deadline` 时效签名，过期需重新取详情；下载须及时。
- 限流 ≥ 15s。

### ⑧ 落点（canonical + 游走边）
- canonical：`platform_content_id`(=`channel_content_id`)、`platform_author_id`(=`channel_account_id`)、`title`、`body_text`、`content_url`(=`content_link`)、`tags`(=`topic_list`)、`video_url`(=`video_url_list[].video_url`)、`audio_url`(=`voice_data.play_url`)、`stats.*`、`publish_ts`。
- 游走边：`video_to_hashtag`(=`topic_list`)、`video_to_author`（落 `channel_account_id` 标识）；`author_to_works` 不可走。

---

## 接口 3：视频下载（m4s 直链）

### ① 身份
- `source_id`: **PLT_BILIBILI_VIDEO_DL**
- 状态：**verified**（`bili_video_dl.json`：`206 / octet-stream / 1MB 真实视频字节`）

### ② 请求标准
- method：`GET`（直连 B站 CDN，不经爬虫网关）
- path：详情返回的 `video_url_list[].video_url`（`*.bilivideo.cn:8082/.../*.m4s`）
- 鉴权：**必须带 `Referer: https://www.bilibili.com/`**（防盗链）；URL 自带 `deadline` 签名。

### ③ 真实 curl
```bash
curl -L 'https://xy115x231x41x20xy.mcdn.bilivideo.cn:8082/v1/resource/upgcxcode/83/03/907810383/907810383_nb3-1-30016.m4s?...' \
  -H 'Referer: https://www.bilibili.com/' \
  -o part_video.m4s
```

### ④ 响应信封 + 翻页
- 二进制流，无 JSON 信封；实测 `HTTP 206 Partial Content`，`Content-Range: bytes 0-1048575/1766147`，`bytes_received=1048576`，`looks_like_video=true`（`bili_video_dl.json`）。

### ⑤ 字段台账（取自 `bili_video_dl.json`）

| 字段名(raw) | 类型 | 含义 | 提取标注 | 真实示例值 |
|---|---|---|---|---|
| `http_status` | int | HTTP 状态 | 直接可用 | `206` |
| `content_type` | string | 内容类型 | 直接可用 | `"application/octet-stream"` |
| `content_range` | string | 字节范围/总长 | 需后处理（解析总长） | `"bytes 0-1048575/1766147"` |
| `bytes_received` | int | 本次收到字节数 | 直接可用 | `1048576` |
| `looks_like_video` | bool | 字节嗅探判定为视频 | 直接可用 | `true` |

### ⑥ 提取与后处理规则
- **下载结论：bili_video_dl 实测 206，可下载**，得到真实视频字节。
- m4s 必须带 `Referer: https://www.bilibili.com/`，否则防盗链拦截。
- DASH 分轨：视频轨 + `voice_data.play_url` 音频轨需分别下载后合并（ffmpeg）。
- **（实测 2026-06-16，新加坡云端）完整下载 + 合并验证通过**：视频轨（`...30016.m4s`）+ `voice_data.play_url` 音轨（`...30216.m4s`）→ `ffmpeg -i v.m4s -i a.m4s -c copy out.mp4` → 合并 mp4 含 `Video h264 (avc1)` + `Audio aac (HE-AAC) 44100Hz stereo`，可直接做原生视频提炼。
- ⚠️ **下载坑（实测）**：`*.mcdn.bilivideo.cn` 节点用 httpx `follow_redirects=True` 会被带到 P2P 死节点、连接超时（两次都卡死）；**改用 curl 且不跟随重定向**即 `206` 秒下。视频轨主 host `upos-sz-mirrorcos.bilivideo.com` 稳定。详见 [视频音频取数实测.md](../视频音频取数实测.md)。
- 大文件用 `Range` 分块续传（`Content-Range` 给出总长 1766147）。

### ⑦ 边界与失败
- `deadline` 过期则直链失效，须回到详情接口重取。
- 限流 ≥ 15s。

### ⑧ 落点（canonical + 游走边）
- canonical：`video_blob`（落地视频文件，供多模态分析）。
- 无新增游走边；属 `video_to_*` 之后的物料下载阶段（提取标注：**需后处理下载**）。
