5.7 KiB
5.7 KiB
腾讯视频 Python 蜘蛛设计
目标
在当前 Python 仓库中新增一个符合 base.spider.Spider 接口的腾讯视频蜘蛛,覆盖以下能力:
- 首页分类与推荐
- 分类列表
- 搜索
- 详情解析
- 播放透传
实现以用户提供的 Node/JS 版本为行为参考,但落地形式遵循当前仓库的单文件 Spider 约定。
范围
本次实现包含:
- 新增独立脚本,文件名为
腾讯视频.py - 首页使用腾讯频道页 HTML 抓取推荐卡片
- 分类页使用腾讯频道页 HTML 抓取卡片并支持常见筛选参数
- 详情页调用
float_vinfo2与批量详情接口,组装单条播放线路 - 搜索调用
MultiTerminalSearch - 播放阶段只做原始链接透传
- 为新增行为补齐
unittest
本次实现不包含:
- 参考代码中的 HTTP 路由导出层
- 任何 parse 相关逻辑
- 解析器线路生成
- 花絮/预告拆分为独立线路
- 公共 helper 抽象
方案选择
候选方案有三种:
- 单文件直译版
- 单文件加
lxml解析列表页 - 站点文件加多个私有 helper 重构
选用方案 1,并保留少量私有 helper。
原因:
- 与用户提供的参考实现最接近
- 列表页测试夹具最容易构造
- 不额外扩大实现范围
模块边界
新增脚本只在站点文件内部维护逻辑,不修改 base/。
Spider 对外方法:
initgetNamehomeContenthomeVideoContentcategoryContentdetailContentsearchContentplayerContent
站点内部私有 helper:
_headers- 统一请求头
_parse_list_items- 从频道页 HTML 中提取卡片
_get_batch_video_info- 批量请求分集信息
_safe_json- 解析 JSON 和 JSONP 载荷
请求与 ID 设计
固定主域:
https://v.qq.com
固定请求头:
User-Agent: PC_UA
vod_id 设计:
- 首页直接使用卡片里的
data-float - 分类页使用
频道$sourceId - 搜索结果直接使用
doc.id
详情阶段:
- 如果传入的是
频道$sourceId,取$后面的值作为cid - 如果没有
$,直接把原值作为cid
首页与分类设计
首页
首页请求:
/x/bu/pagesheet/list?_all=1&append=1&channel=cartoon&listpage=1&offset=0&pagesize=21&iarea=-1&sort=18
解析规则:
- 用正则提取
list_item - 取
img alt作为vod_name - 取
img src作为vod_pic - 取第一个链接文本作为
vod_remarks - 取
a[data-float]作为vod_id
首页只返回:
classlist
不返回 filters。
分类
分类请求基础路径:
/x/bu/pagesheet/list
固定参数:
_all=1append=1channel=<id>listpage=1offset=(page-1)*21pagesize=21iarea=-1
可选筛选参数:
sortiyearyearitypeifeatureiareaitrailergender
分类页返回结构遵循当前参考实现:
listpagepagecountlimittotal
详情设计
详情请求:
https://node.video.qq.com/x/api/float_vinfo2?cid=<targetCid>
详情字段映射:
vod_name <- json.c.titletype_name <- json.typvod_actor <- json.namvod_year <- json.c.yearvod_content <- json.c.descriptionvod_remarks <- json.recvod_pic <- json.c.pic
播放列表生成:
- 读取
json.c.video_ids - 调用批量接口:
https://union.video.qq.com/fcgi-bin/data?...&idlist=<vid1,vid2,...>
- 按原始
video_ids顺序回填标题 - 正片与花絮/预告不拆线路,统一合并为一条
腾讯视频 - 每个播放项格式为:
标题$https://v.qq.com/x/cover/<cid>/<vid>.html
最终详情仅保留一条线路:
vod_play_from = "腾讯视频"
搜索设计
搜索请求:
https://pbaccess.video.qq.com/trpc.videosearch.mobile_search.MultiTerminalSearch/MbSearch?vplatform=2
请求头:
- 桌面浏览器 UA
Content-Type: application/jsonOrigin: https://v.qq.comReferer: https://v.qq.com/
请求体字段沿用参考实现:
versionclientTypequerypagenumpagesizeextraInfo
结果提取:
- 同时遍历
data.normalList.itemList - 同时遍历
data.areaBoxList[].itemList - 只保留
doc.id存在且长度大于 11 的结果 - 标题去掉
<em>标签
分页结构保持参考行为:
listpagepagecountlimittotal
播放设计
用户明确要求:
- 不要 parse 相关内容
- 不保留任何解析器线路
因此 playerContent 只做原始链接透传,固定返回:
parse = 1jx = 1url = idheader = {"User-Agent": "PC_UA"}
不做任何站内解析或解析器回退。
容错策略
- 首页和分类页 HTML 抓取失败时返回空列表
- 批量详情接口单次失败时忽略该批次,保留已成功条目
- 详情接口失败时跳过当前
id - 搜索接口异常时返回空分页结构
- 播放阶段不抛异常,直接透传原始
id
测试设计
新增 tests/test_腾讯视频.py,使用 unittest 与 unittest.mock,不访问真实网络。
首轮测试覆盖:
- 首页 HTML 提取推荐卡片
- 首页返回固定分类
- 分类页正确拼接筛选参数
- 分类页返回
频道$sourceId形式的vod_id _get_batch_video_info解析QZOutputJson=响应- 详情页把正片和花絮/预告合并为单条
腾讯视频线路 - 搜索同时处理
normalList与areaBoxList - 播放透传返回
parse=1/jx=1
风险与边界
- 列表页 HTML 结构若改动,正则提取会失效,但这与参考实现保持一致
- 腾讯搜索返回结构可能包含多种卡片形态,首轮只覆盖参考代码已处理的两种容器
PC_UA是否需要替换成真实 UA 可在实现阶段决定,但行为上保持统一 header 即可