docs: add 四万影视 spider design
This commit is contained in:
@@ -0,0 +1,293 @@
|
||||
# 四万影视 Spider 设计
|
||||
|
||||
## 目标
|
||||
|
||||
在当前 Python 仓库中新增一个符合 `base.spider.Spider` 接口的 `四万影视` spider,参考用户提供的 JS 采集脚本,接入 `https://40000.me/api/maccms`,实现分类、搜索、详情和播放能力。
|
||||
|
||||
## 范围
|
||||
|
||||
本次实现包含:
|
||||
|
||||
- 新增 `py/四万影视.py`
|
||||
- 新增 `py/tests/test_四万影视.py`
|
||||
- 固定主分类与静态筛选
|
||||
- 分类接口请求与列表字段标准化
|
||||
- 搜索接口请求与列表字段标准化
|
||||
- 详情接口请求与多线路播放字段组装
|
||||
- 播放直链透传与非直链 `parse=1` 回退
|
||||
|
||||
本次实现不包含:
|
||||
|
||||
- 首页推荐抓取
|
||||
- 动态分类发现
|
||||
- 站点 HTML 页面解析
|
||||
- 真实联网测试
|
||||
- 第三方解析器实现
|
||||
|
||||
## 目标接口形态
|
||||
|
||||
Spider 将实现以下标准方法:
|
||||
|
||||
- `homeContent(filter)`
|
||||
- `homeVideoContent()`
|
||||
- `categoryContent(tid, pg, filter, extend)`
|
||||
- `searchContent(key, quick, pg="1")`
|
||||
- `detailContent(ids)`
|
||||
- `playerContent(flag, id, vipFlags)`
|
||||
|
||||
遵循当前仓库约定:
|
||||
|
||||
- 单文件 spider
|
||||
- 使用 `fetch` 发起请求,不改共享基类
|
||||
- 列表与搜索结果不返回 `pagecount`
|
||||
- 详情结果使用 `vod_play_from` / `vod_play_url`
|
||||
|
||||
## 分类与筛选
|
||||
|
||||
沿用参考脚本的固定分类 ID 与名称:
|
||||
|
||||
- `20` 电影
|
||||
- `30` 电视剧
|
||||
- `39` 动漫
|
||||
- `45` 综艺
|
||||
- `32` 欧美
|
||||
|
||||
筛选为静态定义,不从远端动态读取。
|
||||
|
||||
每个主分类都返回三类筛选:
|
||||
|
||||
- `subType`
|
||||
- 使用参考脚本中的子分类映射
|
||||
- 默认值为当前主分类 `type_id`
|
||||
- `year`
|
||||
- `全部` 加 `2026` 到 `2000`
|
||||
- `sort`
|
||||
- `time`
|
||||
- `hits`
|
||||
- `score`
|
||||
- `up`
|
||||
|
||||
Python 版本筛选值沿用仓库现有格式:
|
||||
|
||||
- `{"n": "显示名", "v": "实际值"}`
|
||||
|
||||
## 数据模型
|
||||
|
||||
### 列表项
|
||||
|
||||
分类和搜索返回的每个视频项统一标准化为:
|
||||
|
||||
- `vod_id`
|
||||
- `vod_name`
|
||||
- `vod_pic`
|
||||
- `vod_remarks`
|
||||
- `vod_year`
|
||||
- `type_name`
|
||||
|
||||
字段来源以 maccms JSON 为准。
|
||||
|
||||
额外规范:
|
||||
|
||||
- `vod_pic` 为空时回退到 `https://40000.me/public/favicon.png`
|
||||
- `type_name` 优先使用接口值,缺失时按固定主分类映射兜底
|
||||
- `vod_actor` 中的 `'` 还原为 `'`
|
||||
- 演员列表中的逗号空白归一化为英文逗号
|
||||
|
||||
### 详情项
|
||||
|
||||
详情页输出保持仓库当前约定,不保留 JS 版本里的 `vod_play_sources` 数组,而是转换为:
|
||||
|
||||
- `vod_play_from`
|
||||
- `vod_play_url`
|
||||
|
||||
组装规则:
|
||||
|
||||
- 上游 `vod_play_from` 按 `$$$` 拆成线路名
|
||||
- 上游 `vod_play_url` 按 `$$$` 拆成线路内容
|
||||
- 每条线路内部按 `#` 拆分剧集
|
||||
- 每个剧集按 `剧集名$playId` 编码
|
||||
- 若某条线路名缺失,回退为 `线路N`
|
||||
- 若某个剧集标题缺失,回退为 `第N集`
|
||||
|
||||
最终:
|
||||
|
||||
- `vod_play_from = 线路A$$$线路B`
|
||||
- `vod_play_url = 第1集$playId#第2集$playId$$$正片$playId`
|
||||
|
||||
### 播放 ID
|
||||
|
||||
播放 ID 不再额外编码,直接复用接口里的剧集值:
|
||||
|
||||
- 若值本身是 `http/https` 链接,则播放器直接返回
|
||||
- 若值不是完整 URL,则播放器返回 `parse=1` 交给外部解析
|
||||
|
||||
## 请求映射
|
||||
|
||||
Spider 只请求一个接口端点:
|
||||
|
||||
- `https://40000.me/api/maccms`
|
||||
|
||||
### homeContent
|
||||
|
||||
不请求远端,直接返回固定分类和固定筛选。
|
||||
|
||||
### homeVideoContent
|
||||
|
||||
按用户确认,固定返回:
|
||||
|
||||
- `{"list": []}`
|
||||
|
||||
### categoryContent
|
||||
|
||||
请求参数:
|
||||
|
||||
- `ac=detail`
|
||||
- `t=<subType>`
|
||||
- `pg=<page>`
|
||||
- `h=<year>`,仅在年份非空时传入
|
||||
- `by=<sort>`
|
||||
|
||||
其中:
|
||||
|
||||
- `subType` 来自 `extend["subType"]`,缺失时回退 `tid`
|
||||
- `sort` 来自 `extend["sort"]`,默认 `time`
|
||||
- `year` 来自 `extend["year"]`
|
||||
|
||||
返回:
|
||||
|
||||
- `page`
|
||||
- `limit`
|
||||
- `total`
|
||||
- `list`
|
||||
|
||||
`limit` 使用当前返回列表长度,`total` 优先使用接口 `total`,缺失时回退为列表长度。
|
||||
|
||||
### searchContent
|
||||
|
||||
请求参数:
|
||||
|
||||
- `ac=detail`
|
||||
- `wd=<keyword>`
|
||||
- `pg=<page>`
|
||||
|
||||
空关键字直接返回空列表。
|
||||
|
||||
返回:
|
||||
|
||||
- `page`
|
||||
- `limit`
|
||||
- `total`
|
||||
- `list`
|
||||
|
||||
### detailContent
|
||||
|
||||
请求参数:
|
||||
|
||||
- `ac=detail`
|
||||
- `ids=<videoId>`
|
||||
|
||||
流程:
|
||||
|
||||
1. 读取第一条详情记录
|
||||
2. 标准化基础字段
|
||||
3. 解析 `vod_play_from` / `vod_play_url`
|
||||
4. 输出单个详情对象
|
||||
|
||||
重点字段:
|
||||
|
||||
- `vod_id`
|
||||
- `vod_name`
|
||||
- `vod_pic`
|
||||
- `type_name`
|
||||
- `vod_year`
|
||||
- `vod_area`
|
||||
- `vod_director`
|
||||
- `vod_actor`
|
||||
- `vod_content`
|
||||
- `vod_remarks`
|
||||
- `vod_play_from`
|
||||
- `vod_play_url`
|
||||
|
||||
### playerContent
|
||||
|
||||
处理规则保持与参考脚本一致:
|
||||
|
||||
1. 空播放 ID 返回:
|
||||
- `parse = 1`
|
||||
- `jx = 1`
|
||||
- `url = ""`
|
||||
2. 若 `id` 以 `http://` 或 `https://` 开头:
|
||||
- `parse = 0`
|
||||
- `jx = 0`
|
||||
- `url = id`
|
||||
3. 否则:
|
||||
- `parse = 1`
|
||||
- `jx = 1`
|
||||
- `url = id`
|
||||
|
||||
播放器返回头固定包含:
|
||||
|
||||
- `User-Agent`
|
||||
- `Referer: https://40000.me/`
|
||||
|
||||
## 架构与辅助函数
|
||||
|
||||
`py/四万影视.py` 保持单类实现,但拆成小 helper,避免方法过长。
|
||||
|
||||
建议 helper:
|
||||
|
||||
- `_build_filters()`
|
||||
- 生成固定筛选配置
|
||||
- `_type_name_by_id(type_id)`
|
||||
- 固定主分类名称映射
|
||||
- `_normalize_vod(item)`
|
||||
- 统一标准化列表/详情基础字段
|
||||
- `_api_get(params)`
|
||||
- 调用 maccms JSON 接口
|
||||
- 非 200 或非对象响应时抛出 `ValueError`
|
||||
- 上层入口方法负责捕获并返回空结果
|
||||
- `_parse_play_groups(item)`
|
||||
- 把上游播放源字段转换成仓库需要的 `vod_play_from` / `vod_play_url`
|
||||
- `_page_result(items, page, total)`
|
||||
- 构造列表返回体
|
||||
|
||||
## 错误处理
|
||||
|
||||
- 请求失败时不向外抛未处理异常
|
||||
- 分类失败返回:
|
||||
- `{"page": 当前页, "limit": 0, "total": 0, "list": []}`
|
||||
- 搜索失败返回:
|
||||
- `{"page": 当前页, "limit": 0, "total": 0, "list": []}`
|
||||
- 详情失败返回:
|
||||
- `{"list": []}`
|
||||
- 播放失败返回:
|
||||
- `{"parse": 1, "jx": 1, "url": "", "header": {...}}`
|
||||
|
||||
这样与仓库现有 spider 的防御性风格保持一致。
|
||||
|
||||
## 测试策略
|
||||
|
||||
使用 `unittest` 与 `unittest.mock`,不走真网。
|
||||
|
||||
至少覆盖以下行为:
|
||||
|
||||
1. `homeContent` 返回预期分类 ID 与筛选 key
|
||||
2. `_build_filters` 生成 `subType/year/sort` 三组筛选
|
||||
3. `_api_get` 正确请求 `/api/maccms`,并处理非 200 / 非对象响应
|
||||
4. `categoryContent` 正确映射 `subType/year/sort/page`
|
||||
5. `categoryContent` 不返回 `pagecount`
|
||||
6. `searchContent` 正确映射 `wd` 和分页
|
||||
7. `searchContent` 在空关键字时直接返回空列表
|
||||
8. `detailContent` 正确提取详情基础字段并组装 `vod_play_from` / `vod_play_url`
|
||||
9. `_parse_play_groups` 能处理多线路、多剧集、缺失线路名与缺失剧集名
|
||||
10. `playerContent` 对直链返回 `parse=0`
|
||||
11. `playerContent` 对非直链返回 `parse=1`
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 新增 `py/四万影视.py` 和 `py/tests/test_四万影视.py`
|
||||
- 可独立运行 `python -m unittest tests.test_四万影视 -v`
|
||||
- 分类、搜索、详情的离线夹具输出稳定
|
||||
- `homeVideoContent()` 固定返回空列表
|
||||
- 播放器对直链和非直链的行为与参考脚本一致
|
||||
- 不修改共享基类即可完成接入
|
||||
Reference in New Issue
Block a user