| name | analyze-video-url |
| description | Use when the user provides a video share link or playback page URL and wants to analyze which platform it belongs to, whether it's a new link type for an existing channel, or a completely new platform requiring a new parser. Triggers on video URLs, share text containing video links, or requests to analyze/add video platform support. |
视频链接渠道分析
分析视频分享链接或播放页面的渠道归属,判断是已有渠道的新链接类型还是需要新增解析渠道,并生成对应的解析器代码模板。
何时使用
- 用户提供了一个视频分享链接,想知道属于哪个平台
- 用户发现某个链接无法解析,需要分析原因
- 用户想为新平台添加解析支持
- 用户提供的链接可能是已知平台的新入口域名或新 URL 格式
何时不用
- 用户直接要求解析视频(用
parse-video-py parse "链接")
- 用户要求修改已有解析器的逻辑(直接编辑 parser 文件)
- 用户只是询问项目架构(参考 CLAUDE.md)
分析流程
步骤 1:提取 URL
从用户输入中提取目标 URL:
- 如果输入是纯 URL(以
http:// 或 https:// 开头)→ 直接使用
- 如果输入包含混合文本 → 用与
utils.py 一致的正则提取 URL:
https?://[\w.-]+[\w/-]*[\w.-:]*\??[\w=&:\-+%.]*/*
注意:这个正则会正确处理尾部标点、引号等,不要用 https?://[^\s]+ 替代,否则提取结果会与程序实际解析的 URL 不一致
- 提取到 URL 后,进入步骤 2
步骤 2:渠道归属判断(三分类)
按以下阶段顺序执行。所有 URL 都必须完成重定向链分析(阶段 B),即使原始域名已在阶段 A 命中——因为已知短链(如 v.douyin.com)可能重定向到其他平台(如跳到 ixigua.com 走西瓜解析)。
阶段 A:原始域名匹配
- 读取
parser/__init__.py 中 video_source_info_mapping 的所有 domain_list
- 对提取到的 URL 做子串匹配(与
parser/__init__.py 的 parse_video_share_url 函数逻辑一致)
- 记录结果:匹配成功 → 标记为「初始匹配平台」(如
VideoSource.DouYin);不匹配 → 标记为「未知域名」
- 无论阶段 A 是否命中,都必须继续执行阶段 B
阶段 B:重定向链分析(所有 URL 必经)
- 用 HTTP 客户端(
httpx.AsyncClient(follow_redirects=False))请求原始 URL,获取第一跳 Location
- 如果
Location 存在,继续对 Location URL 发起新请求(同样禁用自动重定向),获取下一跳
- 循环执行步骤 2,直到响应不再包含
Location header(到达落地页),或达到最大跳数上限(建议 10 跳防止无限循环)
- 完整记录重定向链中的每一跳 URL
- 对重定向链中的每个 URL(包括最终落地页)做域名匹配(同阶段 A 的逻辑)
- 根据综合结果判定最终分类:
| 阶段 A 结果 | 重定向落地页结果 | 最终分类 | 平台归属 |
|---|
| 命中平台 X | 未重定向或仍命中 X | 已知域名 | 平台 X |
| 命中平台 X | 命中平台 Y(≠X) | 已知域名 | 以落地页为准,归为平台 Y |
| 命中平台 X | 不匹配任何已知平台 | 已知域名 | 平台 X(但落地页结构未知,需在报告中标注) |
| 未命中 | 命中平台 Z | 跳转命中 | 平台 Z,需补充域名注册 |
| 未命中 | 未命中 | → 进入阶段 C | — |
- 分类为「跳转命中」时,记录原始域名(需在
parser/__init__.py 补充注册)和完整重定向路径
- 未命中的情况 → 进入阶段 C
阶段 C:页面结构特征匹配(仅阶段 A 和 B 均未命中时执行)
- 抓取最终落地页 HTML
- 检查是否包含已知平台的数据特征签名:
window._ROUTER_DATA → 抖音系
window.INIT_STATE → 快手
$render_data → 微博
- BV 号格式(
/video/BV\w+)→ B 站
- 特征命中 → 分类为「跳转命中」,记录匹配的平台和特征
- 均不匹配 → 分类为「疑似新平台」
步骤 3:页面抓取与结构深度分析
对目标 URL 进行深入分析,使用 HTTP 客户端(模拟移动端 UA)请求页面。
按以下清单逐项分析并记录结果:
重定向与控制流
- 重定向链:完整记录每跳 URL(原始 → 中间跳 → 落地页)
- 重定向策略:是否需要定制 redirect policy?参考快手只在特定路径才跟随重定向(
kuaishou.py 的重定向处理)
- Host 分发:解析器是否按 host 做分支?参考抖音按 host 分 PC/App(
douyin.py 的 host 分发逻辑)
- URL 路径变换:落地页 URL 是否需要路径替换?参考快手
/fw/long-video/ → /fw/photo/(kuaishou.py)
数据提取
- 嵌入 JSON:HTML 中搜索以下常见签名:
window._ROUTER_DATA = ...</script> → 抖音
window.INIT_STATE = ...</script> → 快手
$render_data = ... → 微博
- 其他
window.__* 模式
- API 端点:是否需要调用独立 API?需要几次请求?
- 单次请求:大部分平台
- 双次请求:B 站(先 view API 拿 CID,再 playurl API 拿视频地址,参考
bilibili.py)
- 视频 ID 格式:ID 在 URL 路径中的位置,提取正则
关键字段定位
在找到的 JSON 数据中定位以下字段的具体路径:
- 视频播放地址:
video.play_addr.url_list.0(抖音风格)或 mainMvUrls.0.url(快手风格)
- 标题/描述:
desc(抖音)或 caption(快手)
- 封面图:
video.cover.url_list.0(抖音)或 coverUrls.0.url(快手)
- 作者信息:
author.nickname / author.avatar_thumb.url_list.0 / author.sec_uid
反爬特征
- 是否需要特殊参数?(如抖音图集的
a_bogus、web_id)
- 是否需要特定 Cookie 或 Referer?(如 B 站需要
Referer: https://www.bilibili.com/)
- 是否需要桌面端 UA 而非移动端?
步骤 4:生成分析报告
在对话中输出以下格式的结构化报告。每份报告必须包含全部 6 个字段,缺失任意一项视为不通过:
## 视频链接分析报告
**输入 URL**: [原始输入]
**提取 URL**: [从输入中提取的 URL]
### 1. 渠道分类
[已知域名 / 跳转命中 / 疑似新平台]
### 2. 平台标识
[命中时给出 VideoSource 枚举,如 VideoSource.DouYin。疑似新平台时写"未知"]
### 3. 重定向链
- 原始 URL: [URL]
- 跳转 1: [URL] (如有)
- 落地页: [最终 URL]
### 4. 数据提取策略
[重定向提取 ID / HTML 嵌入 JSON / API 调用 / 混合模式]
- 推荐解析模式: [具体说明]
- HTTP 客户端: httpx.AsyncClient
- JSON 解析: 标准 JSON 字典访问
### 5. 关键字段路径
- 视频地址: [JSON 路径]
- 标题: [JSON 路径]
- 封面: [JSON 路径]
- 作者 UID: [JSON 路径]
- 作者名: [JSON 路径]
- 作者头像: [JSON 路径]
### 6. 待修改文件清单
[列出所有需要新建或修改的文件路径,包括 parser/__init__.py、parser/base.py、parser/<platform>.py、tests/test_<platform>.py、README.md]
报告输出后,询问用户是否继续生成代码。
步骤 5:生成代码
根据渠道分类结果,生成对应的代码变更。所有变更组织为一次 patch,经用户确认后才写入。
已知域名(已有渠道扩展)
分析现有解析器是否已覆盖该 URL 格式。如果未覆盖,生成以下扩展:
parser/__init__.py 变更:在对应平台的 domain_list 中添加新域名
- 解析器 host 分支扩展:参考
douyin.py 的 host 分发模式,在现有解析器的 parse_share_url 方法中添加新 host 的处理分支
- 新的重定向策略(如需要):参考
kuaishou.py 的定制 redirect 处理
- 新的 URL 路径变换(如需要):参考
kuaishou.py 的路径替换
- 新数据提取路径(如页面结构与现有逻辑不同)
不得仅修改 parser/__init__.py 而忽略运行时的 host 分发和控制流逻辑。
跳转命中(域名补充)
生成以下变更:
parser/__init__.py 变更:在命中平台的 domain_list 中添加原始域名
- 解析器扩展(如需要):如果原始域名对应的新 host 需要不同的处理逻辑,在解析器中添加分支
疑似新平台(完整解析器)
根据步骤 3 的分析结果,选择最合适的解析模式生成完整解析器:
解析模式选择决策树:
- URL 是短链且重定向到含视频 ID 的页面 → 短链重定向模式(参考
twitter.py 或 douyin.py)
- 落地页 HTML 中有
window.* 嵌入 JSON → HTML 嵌入 JSON 模式(参考 kuaishou.py)
- 有公开 API 端点可用 → API 调用模式(参考
bilibili.py)
- 以上混合 → 混合模式(参考
douyin.py 的图集处理)
生成文件清单:
-
parser/<platform>.py:完整解析器,遵循以下规范:
- 继承
BaseParser:class <Platform>(BaseParser):
- 实现
async def parse_share_url(self, share_url: str) -> VideoInfo 方法
- 可选实现
async def parse_video_id(self, video_id: str) -> VideoInfo 方法
- HTTP 客户端使用
httpx.AsyncClient
- JSON 解析使用标准 JSON 字典访问
- 使用
self.get_default_headers() 获取默认请求头
- 中文注释标注关键流程
- 错误信息使用中文
-
parser/base.py 变更:
- 在
VideoSource 枚举中添加新平台:<Platform> = "<platform>" # 平台名
-
parser/__init__.py 变更:
- 添加新解析器的 import
- 在
video_source_info_mapping 中添加映射条目,包含域名列表和解析器类
-
tests/test_<platform>.py:
- URL/ID 提取函数的纯单元测试(不依赖外部网络)
- 正则/路径匹配的单元测试
- mock httpx 的 API 响应解析测试
- 不生成真实 URL 的集成测试
-
README.md 变更:
步骤 6:代码审查与确认
所有代码变更都必须经用户确认后才写入文件。
- 在对话中展示完整的代码和变更说明(含所有涉及的文件)
- 将所有变更组织为一次 patch:
parser/<platform>.py(新解析器或已有解析器扩展)
parser/base.py(枚举变更)
parser/__init__.py(映射条目变更)
tests/test_<platform>.py(测试文件)
README.md(支持平台表格新增行)
- 等待用户确认后才执行文件写入
- 写入后运行
pytest -v 验证测试通过
- 写入后运行
black --check . && isort --check . && flake8 . 验证格式检查通过
解析模式参考索引
生成代码时,按以下参考文件选择最接近的模式:
短链重定向 + ID 提取模式
参考文件: parser/twitter.py
适用场景: 短链需要跟随重定向,从重定向目标 URL 中提取视频 ID
关键模式:
follow_redirects=False 禁止自动跟随
- 从响应 headers 中获取重定向目标
- 正则提取 ID
- 调用
parse_video_id 获取视频信息
参考文件: parser/douyin.py
适用场景: 短链重定向后可能跨平台(如抖音→西瓜)
关键模式:
- 检查重定向目标 host 做平台分发
- 路径解析提取视频 ID
HTML 嵌入 JSON 模式
参考文件: parser/kuaishou.py
适用场景: 落地页 HTML 中嵌入 window.* JSON 数据
关键模式:
- 定制重定向处理
- URL 路径替换
- 正则提取
window.INIT_STATE = (.*?)</script>
- 遍历 JSON 顶层 map 查找包含
result 和 photo 键的对象
- 字典路径提取各字段
参考文件: parser/douyin.py
适用场景: 页面有 window._ROUTER_DATA,且可能有图集
关键模式:
- 先检查 canonical 判断是否是图集(note)
- 图集走独立 API(构造 URL 含随机参数)
- 视频/非图集走
window._ROUTER_DATA 提取
API 调用模式
参考文件: parser/bilibili.py
适用场景: 有公开 API 可直接调用
关键模式:
- 使用
httpx.AsyncClient
- 标准 JSON 字典访问
- 双次请求:先 view API 获取 CID,再 playurl API 获取视频地址
- 短链(
b23.tv)先跟随重定向提取 BVID
项目公共数据结构
参考文件: parser/base.py 和 parser/__init__.py
VideoSource: 平台枚举
VideoInfo: 统一返回数据类
VideoAuthor: 作者信息数据类
ImgInfo: 图片信息数据类
video_source_info_mapping: 平台到域名和解析器的映射
BaseParser.get_default_headers(): 获取默认请求头(fake-useragent)
Red Flags(分析过程中的警告信号)
分析时如果出现以下情况,需要在报告中明确指出:
| 信号 | 可能的问题 | 处理方式 |
|---|
| 页面返回空白或 JS 渲染内容 | 平台需要 JS 执行,静态抓取无法获取数据 | 在报告中标注"可能需要 headless browser 或 API 调用" |
| 重定向到登录页 | 需要登录态才能获取内容 | 在报告中标注"需要登录态" |
| HTML 中没有嵌入 JSON | 可能是纯 API 驱动的 SPA | 尝试从网络请求中推断 API 端点 |
| 已知域名的 host 未被解析器覆盖 | parser/__init__.py 有域名但解析器的 host 分发没有该分支 | 报告为"已知域名,但解析器缺少该 host 分支",生成 host 扩展代码 |
| 多个平台共享相似短链 | 短链可能跳转到不同平台(如抖音→西瓜) | 报告中明确"平台归属以重定向落地页为准" |
常见错误(代码生成时避免)
- 只改
parser/__init__.py 不改解析器:添加域名后,解析器的 parse_share_url 如果有 host 分发逻辑,必须同步添加新 host 分支
- 忽略重定向策略差异:快手需要定制 redirect 处理,不是简单的
follow_redirects=False
- 生成真实 URL 集成测试:测试应使用纯单元测试 + mock httpx,不依赖外部网络
- 固定平台归属:
v.douyin.com 不一定总是抖音,可能跳转到西瓜,必须跟随重定向判断