批量下载 B站字幕:限流排查与「假残缺」识别实战
# 批量下载 B站字幕:限流排查与「假残缺」识别实战
> 摘要:批量下载 127 个视频的 B站 AI 字幕,最坑的不是接口,而是"看起来缺字幕"。本文拆解两个高频坑:限流导致字幕 URL 为空、以及"假残缺"——字幕轨道明明存在,却只能拉到几条。给出完整的识别方法和重试策略,读完可直接复现。
## 背景
拿到 UP 主视频列表(见系列前一篇)后,下一步是批量下载字幕。B站字幕获取链路是:`view` 接口拿 cid → `player/v2` 拿字幕列表 → 下载字幕 JSON。链路不复杂,但**批量**场景下风控和限流会让成功率暴跌——最迷惑的是:字幕明明存在,下载下来却只有几条。
## 正文
### 1. 字幕获取链路
```python
# 1. view 接口: bvid -> cid
d = session.get('https://api.bilibili.com/x/web-interface/view',
params={'bvid': bvid}).json()
cid = d['data']['cid']
# 2. player/v2: 拿字幕列表
d2 = session.get('https://api.bilibili.com/x/player/v2',
params={'bvid': bvid, 'cid': cid}).json()
subs = d2['data']['subtitle']['subtitles'] # [{lan, lan_doc, subtitle_url}, ...]
# 3. 下载字幕 JSON (body 数组 -> SRT)
r = session.get(subtitle_url).json()
for item in r['body']:
# item: {from, to, content}
```
三个关键点:
- **必须带登录 cookie(SESSDATA)**:匿名请求 `player/v2` 返回的字幕列表为空
- **优先选中文轨道**:`lan` 以 `zh` 开头的(`ai-zh`/`zh-Hans`),其次再选其它
- **`subtitle_url` 是带 `auth_key` 的临时地址**,有时效
### 2. 限流症状与识别
批量下载时的两个典型症状:
| 症状 | 现象 | 原因 |
|------|------|------|
| URL 为空 | `subtitle_url` 是空字符串 | B站对高频请求的降级响应 |
| 内容为空 | URL 有效但 JSON 无 `body` | 同上,降级到空内容 |
识别方法:**单个视频单独请求一次**,对比轨道列表和条数。如果单独请求能拿到几百条,批量时只有几条——这就是限流,不是视频本身缺字幕。
### 3. "假残缺":本次实战最深的坑
下载 128 个视频后做质量检查,发现 14 个视频字幕条数异常少(1~43 条)。按直觉会判断"这些视频字幕不完整"。
但单独复查轨道后发现:
```
BV12RYTzeEBy | 下载时 6 条 | 单独请求 373 条
BV1XYq9Y6E4y | 下载时 6 条 | 单独请求 581 条
BV1E6vzBwE2M | 下载时 9 条 | 单独请求 731 条
```
**结论:批量下载时 B站返回了截断/部分内容,单独请求才是完整数据。** 这就是"假残缺"——不是视频没字幕,是批量场景下被限流喂了部分数据。
诊断方法:
```python
# 对条数异常的 srt 做二次核验: 单独请求轨道并统计 body 条数
r = session.get(subtitle_url).json()
n = len(r.get('body') or []) # 对比现有 srt 的 ' --> ' 出现次数
```
### 4. 重试策略(实战有效)
针对限流,最终采用的重试策略:
- 每个视频最多尝试 12 次,**间隔递增**(`8s + attempt * 3s`)
- URL 为空 → 等待后**重新请求 player/v2**(拿新 URL,旧 URL 可能已失效)
- 内容为空 → 等待后重新下载(部分返回的数据不能直接用)
- 条数异常的 srt 单独重跑,直到条数与单独请求一致
```python
for attempt in range(12):
# 拿轨道 -> 若 url 空: sleep(8 + attempt*3); continue
# 下载 -> 若 body 空: sleep(8 + attempt*3); continue
# 成功则 break
```
实测效果:首批 24/32 成功率,重试后 128 个视频全部拿到完整字幕(其中 127 个走 B站字幕,1 个走转写兜底,见系列第三篇)。
## 踩坑记录
1. **不要对"条数少"直接下结论**——先单独请求核验,区分"真残缺"(轨道不存在)和"假残缺"(限流部分返回)
2. **限流是递增惩罚**:连续高频请求会越来越严,间隔要递增而不是固定
3. **字幕 URL 要每次重取**:缓存的 URL 可能已过期或指向降级内容
## 总结
- 批量下载字幕的正确姿势:带 cookie → 选中文轨道 → 限流递增重试
- "假残缺"是最容易误判的坑:**轨道列表完整 ≠ 下载内容完整**,务必核验 body 条数
- 质量检查不能只看"文件存在",要看条数是否合理
下一步:遇到视频真的没有字幕轨道怎么办?音频转写兜底方案见系列第三篇。

浙公网安备 33010602011771号