8.2 KiB
8.2 KiB
不太灵 Python 爬虫设计
目标
在当前 Python 仓库中新增一个符合 base.spider.Spider 接口的不太灵站点爬虫,直接对接 https://web5.mukaku.com/prod/api/v1/,覆盖以下能力:
- 首页分类
- 首页推荐
- 分类列表
- 搜索
- 详情解析
- 网盘分享链接透传播放
实现以用户提供的 JS 版本为行为参考,但最终产物遵循当前仓库的单文件 Spider 约定,不引入 JS 端的网盘驱动依赖。
范围
本次实现包含:
- 新增独立脚本,文件名为
不太灵.py - 使用单一 API 根地址
https://web5.mukaku.com/prod/api/v1/ - 支持
home/category/detail/search/player主链路 - 首页返回固定五个分类
- 电影和电视剧支持 API 筛选参数映射
- 详情页提取影片元数据和网盘分享资源
- 网盘资源按分享链接独立成线路
playerContent对分享链接做原样透传- 为新增行为补齐
unittest
本次实现不包含:
- 参考 JS 中的磁力画质线路输出
- 网盘驱动匹配、
getVod预解析或play二次解析 - 提取码自动补链
- 浏览器执行、反爬绕过或多域名探活
- 修改
base/公共层
方案选择
采用仓库现有的“单站点单文件 + 单测”方案:
- 对外保持
Spider接口兼容 - 对内拆分为 API 请求、参数归一、列表项归一、分页处理、网盘类型识别、详情播放源提取几个 helper
- 保留参考 JS 的核心接口映射和过滤参数含义,但输出改为仓库可直接消费的
vod_play_from/vod_play_url
不复刻参考 JS 的驱动解析逻辑,原因是:
- 当前 Python 仓库没有对应的运行时网盘驱动注入机制
- 用户已明确要求“直接返回分享链接”
- 单测应保持纯离线,不依赖外部驱动行为
模块边界
新增脚本只在站点文件内部维护逻辑,不修改 base/。
脚本内部职责拆分如下:
init- 初始化 API 地址、鉴权参数、请求头、分类和缓存
homeContent- 返回固定
class,并附带电影/电视剧筛选项
- 返回固定
homeVideoContent- 调用热门接口,返回首页推荐
categoryContent- 根据分类和扩展参数请求对应 API,并归一化结果
searchContent- 请求搜索接口,做名称过滤、本地去重和分页
detailContent- 请求详情接口,提取影片元数据与网盘分享线路
playerContent- 对分享链接直接透传
- 私有辅助函数
- 构造带鉴权的 API URL
- 发送请求并解析 JSON
- 归一化列表与详情对象
- 解析扩展筛选参数
- 本地去重与分页
- 识别网盘类型并构造播放线路
API 与请求策略
固定配置如下:
- API 根地址:
https://web5.mukaku.com/prod/api/v1/ app_id:83768d9ad4identity:23734adac0301bccdcb107c4aa21f96c
接口映射如下:
homeContentgetVideoTypeList
homeVideoContentgetVideoList,参数sc=3
categoryContent- 电影、电视剧:
getVideoMovieList - 热门分类:
getVideoList
- 电影、电视剧:
searchContentgetVideoList
detailContentgetVideoDetail
请求原则:
- 统一通过
self.fetch发起 GET 请求 - 超时固定为 10 秒
- 请求头包含桌面浏览器
User-Agent - JSON 解析兼容普通 JSON 字符串和带
callback(...)包装的响应 - 请求失败时返回空列表或空对象,不抛出未处理异常
- 不额外引入重试和持久缓存
分类与筛选设计
首页固定分类为:
1 -> 电影2 -> 电视剧3 -> 近日热门4 -> 本周热门5 -> 本月热门
homeContent 返回:
classfilters
筛选项只对电影和电视剧提供,来源于 getVideoTypeList,字段沿用参考实现:
sc影视类型sd制片地区se上映年份sf资源画质sh影视标签sg排序方式iswp仅网盘资源status剧集状态,仅电视剧可用
筛选值归一原则:
不限、0、空字符串统一视为未设置- 排序默认值使用
1 iswp只接受0/1ext兼容 JSON、URL 编码 JSON 和 Base64 JSON
列表、搜索与分页设计
列表项统一映射为:
vod_id- 使用上游
doub_id
- 使用上游
vod_name- 使用
title
- 使用
vod_pic- 使用
image或epic
- 使用
vod_remarks- 优先
ejs,回退zqxd
- 优先
vod_year- 使用
years
- 使用
vod_content- 使用
abstract
- 使用
vod_actor- 使用
performer
- 使用
vod_director- 使用
director
- 使用
vod_area- 使用
production_area
- 使用
分类处理分两类:
- 电影、电视剧
- 直接使用后端分页接口
getVideoMovieList - 单页结果按
doub_id去重 - 返回
page/limit/total/list
- 直接使用后端分页接口
- 热门分类
- 因上游分页不稳定,固定抓取较大批量结果后本地去重和分页
- 返回
page/limit/total/list
搜索处理规则:
- 调用
getVideoList - 为避免非标题命中造成噪声,额外按标题包含关键字做一次过滤
- 结果按
doub_id去重 - 再做本地分页
为了符合仓库当前约定,分类和搜索结果不返回 pagecount。
详情页设计
详情页输出单个视频对象,字段至少包含:
vod_idvod_namevod_picvod_remarksvod_yearvod_contentvod_actorvod_directorvod_areavod_play_fromvod_play_url
详情数据源直接使用 getVideoDetail 返回对象,不依赖列表缓存。
播放源策略只处理 movies_online_seed:
- 忽略参考 JS 中的
ecca和all_seeds磁力资源 - 遍历
movies_online_seed的每个分享项 - 每个有效分享链接独立生成一条线路
- 线路名格式为
驱动类型#序号,例如quark#1、baidu#2 - 如果无法识别类型,则归类为
other#序号 - 同一链接去重,避免详情页重复输出
vod_play_from 示例:
baidu#1$$$quark#1$$$aliyun#1
vod_play_url 示例:
baidu#1$https://pan.baidu.com/s/xxx$$$quark#1$https://pan.quark.cn/s/yyy
网盘类型识别设计
按分享链接域名识别常见网盘类型:
pan.quark.cn->quarkpan.baidu.com->baidupan.xunlei.com->xunleiwww.alipan.com或aliyundrive.com->aliyun123865.com、123684.com、123pan.com->a123- 其余 ->
other
如果 API 返回的分组名本身包含可用类型,但链接域名识别不到,则回退使用分组名归一后的结果。
播放设计
playerContent 不做任何解析:
- 如果传入的是普通分享链接,直接返回
{"parse": 0, "url": link} - 如果未来上层传入了
push://前缀,也兼容去前缀后返回原始分享链接
本次不支持:
- 直链视频嗅探
- 网盘二次跳转
- 播放头注入
- 网盘分享码自动处理
错误处理设计
错误处理以“返回空结果,不中断链路”为原则:
- API 请求失败
- 列表接口返回空列表
- 详情接口返回空对象,
detailContent最终返回空列表
- JSON 解析失败
- 记录日志后按空结果处理
- 详情中无网盘资源
- 返回正常元信息,
vod_play_from和vod_play_url置空
- 返回正常元信息,
- 搜索关键字为空
- 直接返回空列表
测试设计
按 TDD 补充 py/tests/test_灵机搜盘.py,全部使用 unittest.mock 隔离网络请求。
首批测试覆盖:
homeContent返回固定分类,并只给电影、电视剧生成筛选项。homeVideoContent使用sc=3请求热门列表并归一化字段。categoryContent在电影分类下正确构造筛选参数,并且不返回pagecount。categoryContent对热门分类执行本地去重分页。searchContent对标题关键字做二次过滤并去重。detailContent能把多个网盘链接拆成独立线路并生成quark#1这类线路名。detailContent忽略磁力资源,只保留网盘分享链接。playerContent直接透传分享链接或去掉push://前缀。- 网盘类型识别覆盖百度、夸克、迅雷、阿里、123 盘和兜底类型。
实施约束
- 文件命名使用中文站点名:
不太灵.py - 保持 helper 粒度适中,避免把 API 参数、详情播放源和分页逻辑堆在单个大函数里
- 不修改现有 Spider 的行为
- 先写测试并验证失败,再写实现代码