# 快手/视频号 URL 解包与 OSS 验证报告（2026-06-17）

## 1. 目标与边界

本轮目标是先把快手/视频号搜索与详情回包里的 URL 结构解析清楚，再用 OSS v2 批量验证“推荐规则选中的正片 URL 是否真的可归档”。本轮不修改生产 `play_url` 抽取逻辑，只做事实核验、交叉验证、诊断工具和文档更新。

完整原始响应、临时 URL、OSS 原始响应只保存在 gitignore 下的 `data/platform_url_probe/20260617_115219/`。本文只记录脱敏摘要、字段路径、host、HTTP 状态、Range 状态和统计。

## 2. Sub-agent 交叉结论

### 需求审计

- 本轮先结构解析，再对 selected URL 做 OSS v2 批量验证。
- 历史 run 固定为快手 `v1_run_94448252f5cd`、视频号 `v1_run_35f4f7ccd1cc`。
- 视频号也要扫描广告/素材 MP4，不能默认只有快手有广告素材。
- 本轮不修改生产 `play_url` 抽取逻辑，不提交完整临时 URL。

### 代码审计

- 快手当前生产抽取：`content_agent/integrations/kuaishou.py` 的 `_extract_play_url()` 取 `video_url_list[0].video_url`。
- 视频号当前生产抽取：`content_agent/integrations/shipinhao.py` 取 `video_url_list[0].video_url`。
- builder 只把 client 归一化后的 `play_url` 写入 media record。
- 现有 `platform_raw_payload` 只保留 `channel_content_id/channel_account_id`，不能完整反查原始字段路径。
- OSS 当前会把 `play_url` 传给 `oss_upload.upload_video_from_env()`；Gemini 优先用 `oss_url`，否则 fallback 到 `play_url`。

### 历史 run 审计

- 快手 `TECHNICAL_RETRY_REQUIRED=14`：8 条 `no_play_url`，6 条 Gemini/OpenRouter 错误；技术重试直接原因不是 OSS。
- 视频号 `TECHNICAL_RETRY_REQUIRED=6`：决策层直接原因是 Gemini/OpenRouter；但 30 条 media 全部为 `oss_upload_pending + oss_upload_response_invalid`。
- 两个历史 run 都不能从 runtime 反查 selected URL 的原始字段路径。

### 文档/台账审计

- 旧台账说明快手/视频号直链可下载，但没有把“直链可下载”“Gemini 可下载”“OSS 可转存”拆开记录。
- 快手文档建议下载带 Range/Referer/UA，但当前 `video_fetch` 快手默认头与文档不完全一致。
- 视频号直链需 `Referer: https://channels.weixin.qq.com/` 用于本机下载；OSS v2 是否接受 headers/referer 需要单独验证。

## 3. 历史 run 对照

### 快手 `v1_run_94448252f5cd`

- 决策统计：`ADD_TO_CONTENT_POOL=8`、`KEEP_CONTENT_FOR_REVIEW=9`、`REJECT_CONTENT=6`、`TECHNICAL_RETRY_REQUIRED=14`。
- 媒体状态：`oss_uploaded=29`、`unavailable=8`。
- OSS/媒体错误：`oss_upload_http_error=1`、`no_play_url=8`。
- play_url host：`cc1.xyydnode.com=7`、`v5.oskwai.com=5`、`v4.kwaicdn.com=8`、`v23-3.kwaicdn.com=9`。
- 字段路径证据不足：历史 runtime 无完整上游 raw item。

### 视频号 `v1_run_35f4f7ccd1cc`

- 决策统计：`ADD_TO_CONTENT_POOL=10`、`KEEP_CONTENT_FOR_REVIEW=5`、`REJECT_CONTENT=9`、`TECHNICAL_RETRY_REQUIRED=6`。
- 媒体状态：`oss_upload_pending=30`。
- OSS/媒体错误：`oss_upload_response_invalid=30`。
- play_url host：`findermp.video.qq.com=30`。
- 字段路径证据不足：历史 runtime 无完整上游 raw item。

## 4. 真实接口结构探测

### 快手

- 真实搜索 query：10 个。
- 搜索 item 样本：60 条。
- URL 候选统计：`page=89`、`image=80`、`video_candidate=75`、`audio=1`。
- selected URL：50 条。
- selected 路径：`$.detail.video_url_list[0].video_url=25`、`$.search.video_url_list[0].video_url=25`。
- selected host：`tymov2.a.kwimgs.com=17`、`hwmov.a.yximgs.com=7`、`v23-3.kwaicdn.com=5`、`v2.oskwai.com=6`、`ucmov.a.kwimgs.com=5`、`dxsc.oppass.cn=4`、`v4.kwaicdn.com=3`、`cc1.xyydnode.com=2`、`v1.oskwai.com=1`。

### 视频号

- 真实搜索 query：10 个。
- 搜索页数：18 页。
- 搜索 item 样本：46 条。
- URL 候选统计：`image=95`、`video_candidate=41`、`audio=2`。
- selected URL：41 条。
- selected 路径：`$.search.video_url_list[0].video_url=41`。
- selected host：`findermp.video.qq.com=41`。
- 本轮保留 25011 retry：例如 `怀旧经典歌曲` page1 前两次 25011，第三次成功；`怀旧金曲` 重试后仍 25011，最终 item_count=0。

## 5. OSS v2 批量验证

### 第一组：生产当前 payload 形态

生产当前链路会把 `referer` 作为 dict 字段传给 OSS v2。

- 快手：20 条 selected URL 均 HTTP 200，但没有 `oss_object.cdn_url`，分类为 `oss_upload_response_invalid`。
- 视频号：20 条 selected URL 均 HTTP 200，但没有 `oss_object.cdn_url`，分类为 `oss_upload_response_invalid`。
- 抽样复打快手 selected URL 时，OSS body 为 `status=10000`、`oss_object=null`，错误包含 `dict object has no attribute encode`。

### 第二组：no-referer payload 复验

同一批 raw 样本重新抽 selected URL，去掉 `referer` 字段后调用 OSS v2，并发 2。

- 快手：20/20 成功返回 `oss_object.cdn_url`。耗时约 0.891s 到 119.923s。
- 视频号：20/20 成功返回 `oss_object.cdn_url`。耗时约 1.078s 到 19.248s。

结论：本轮推荐规则选出的 selected URL 能被 OSS v2 成功归档。历史/生产里的 `oss_upload_response_invalid` 更像 OSS v2 payload 兼容问题，不是 URL 字段拆错。

## 6. 推荐解包规则

### 快手

- 优先 detail 正片 URL：`$.detail.video_url_list[].video_url`。
- detail 不可用时 fallback search 正片 URL：`$.search.video_url_list[].video_url`。
- 不默认 `video_url_list[0]` 永远正确；多个候选按路径、HTTP 200/206、`content_type=video/mp4`、Range、duration、host 稳定性排序。
- 过滤 `content_link`、`image_url_list`、头像、`bgm_data.play_url`、广告/素材字段。

### 视频号

- 优先 `$.search.video_url_list[].video_url` 中的 findermp 正片 URL。
- 同样过滤封面、头像、音频/BGM、页面链接、广告/素材字段。
- 广告关键词匹配不能用裸 `ad` 子串，否则会误伤 `stodownload/head` 这类正常 URL。
- 本机下载/轻量验证继续带 `Referer: https://channels.weixin.qq.com/`；OSS v2 转存 payload 不应直接传 dict 型 `referer`。

## 7. 生产改造建议

1. 先修 OSS v2 payload：不要把 `referer` dict 直接传给 OSS v2。若上传服务需要 headers，需约定可编码字段格式，例如字符串 referer 或 `headers` object。
2. 再补 runtime raw payload：记录 `selected_path`、`selected_host`、`probe_status`、`content_type`、`content_range`、`oss_payload_mode`、`oss_failure_type`。
3. 最后改平台 adapter：快手 detail 优先、search fallback；视频号 findermp 正片优先；统一做 URL 候选分类过滤。

## 8. 验证命令

```bash
.venv/bin/python -m pytest tests/test_platform_video_url_candidates.py -q
CONTENT_AGENT_OSS_UPLOAD_URL=http://crawler-upload-v2.aiddit.com/crawler/oss/upload_stream \
  .venv/bin/python tests/test_platform_video_url_candidates.py \
  --real-probe --probe-oss --items-per-query 6 \
  --kuaishou-detail-limit-per-query 3 \
  --oss-limit-per-platform 20 --oss-timeout-seconds 180
```
