docs: add dyrs spider design
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
# 电影人生 Spider 设计
|
||||
|
||||
## 目标
|
||||
|
||||
在当前 Python 仓库中新增一个符合 `base.spider.Spider` 接口的 `电影人生` spider,参考用户提供的 JS 站点逻辑,实现首页、分类、搜索、详情和播放能力,目标站点为 `https://dyrsok.com`。
|
||||
|
||||
## 范围
|
||||
|
||||
本次实现包含:
|
||||
|
||||
- 新增 `py/电影人生.py`
|
||||
- 新增 `py/tests/test_电影人生.py`
|
||||
- 固定 4 个主分类与静态筛选项
|
||||
- 首页推荐、分类页与搜索页卡片解析
|
||||
- 详情页元数据与多线路剧集解析
|
||||
- 播放页 `/api/m3u8` 提取、重定向跟随和主清单二次解析
|
||||
|
||||
本次实现不包含:
|
||||
|
||||
- 修改 `py/base/` 共享基类
|
||||
- 接入 JS 版本中的 `OmniBox.log`、播放历史、媒体信息探测
|
||||
- 真实联网测试
|
||||
- 站外解析器或额外第三方线路适配
|
||||
|
||||
## 分类与筛选
|
||||
|
||||
固定返回以下分类:
|
||||
|
||||
- `dianying` 电影
|
||||
- `dianshiju` 电视剧
|
||||
- `dongman` 动漫
|
||||
- `zongyi` 综艺
|
||||
|
||||
筛选结构采用静态定义,保持与参考脚本一致的语义:
|
||||
|
||||
- `class`
|
||||
- 不同主分类下返回预设类型值
|
||||
- `sort_field`
|
||||
- 默认、热度、更新时间
|
||||
|
||||
Python 版本沿用仓库现有格式,即筛选值使用 `{"n": "...", "v": "..."}`。
|
||||
|
||||
## 接口映射
|
||||
|
||||
- `homeContent`
|
||||
- 返回固定分类和筛选配置
|
||||
- 可附带首页推荐列表
|
||||
- `homeVideoContent`
|
||||
- 请求首页
|
||||
- 复用卡片解析函数返回推荐列表
|
||||
- `categoryContent`
|
||||
- 构造 `/{categoryId}.html`,并按筛选拼接查询参数
|
||||
- 解析卡片并返回分页字段
|
||||
- `detailContent`
|
||||
- 请求详情页
|
||||
- 解析标题、封面、简介、年份、地区、语言、导演、主演、标签
|
||||
- 解析多线路及每条线路下的剧集
|
||||
- `searchContent`
|
||||
- 构造 `/s.html?name=<keyword>`
|
||||
- 解析卡片并执行结果精排
|
||||
- `playerContent`
|
||||
- 输入为详情页剧集项里编码的播放上下文
|
||||
- 请求播放页并提取 `/api/m3u8?origin=...&url=...`
|
||||
- 跟随 302 或 Location 跳转
|
||||
- 若主清单中存在 `raw=1` 子清单,则继续下钻到最终可播 m3u8
|
||||
- 失败时回退为 `parse=1`
|
||||
|
||||
## 数据模型
|
||||
|
||||
### 列表卡片
|
||||
|
||||
列表、首页推荐和搜索统一复用卡片解析逻辑:
|
||||
|
||||
- 从 `a[data-url][title]` 提取标题和详情链接
|
||||
- 仅保留命中 `/dyrscom-` 的详情链接
|
||||
- 图片优先取 `data-src`,其次 `src`
|
||||
- 备注优先取角标文本
|
||||
- 补全相对链接与相对图片地址
|
||||
|
||||
`vod_id` 保留站内短路径,不返回绝对 URL。
|
||||
|
||||
### 详情
|
||||
|
||||
详情页字段按“DOM 优先、正则兜底”的策略提取:
|
||||
|
||||
- 标题优先 `h1/h2`,再回退到 `title`
|
||||
- 封面优先 `og:image`,再回退到详情主图
|
||||
- 简介优先“剧情简介”区域,回退到 `description`
|
||||
- 年份、地区、语言、更新时间通过标签文本或正则抽取
|
||||
- 导演、主演、标签通过各自区块中的链接文本抽取
|
||||
|
||||
播放线路通过详情页上的 `origin` 链接展开:
|
||||
|
||||
- 收集 `originTabs` 中的线路入口
|
||||
- 每条线路单独抓取页面
|
||||
- 在 `.seqlist` 中提取剧集
|
||||
- 剧集 ID 使用 JSON 串编码,至少携带:
|
||||
- `title`
|
||||
- `origin`
|
||||
- `page`
|
||||
- `vodName`
|
||||
- `pic`
|
||||
|
||||
最终输出为仓库当前通用格式:
|
||||
|
||||
- `vod_play_from`: `$$$` 拼接线路名
|
||||
- `vod_play_url`: `$$$` 拼接每条线路的 `剧集名$playId`
|
||||
|
||||
## 搜索精排
|
||||
|
||||
搜索结果在卡片解析后再做一次轻量精排,以贴近参考脚本行为:
|
||||
|
||||
- 先标准化关键词和片名
|
||||
- 去除空白、标点与部分年份噪音
|
||||
- 完全匹配优先
|
||||
- 前缀匹配次之
|
||||
- 包含匹配再次之
|
||||
- 若所有项都未命中,则回退原始顺序
|
||||
|
||||
## 播放解析
|
||||
|
||||
播放解析只实现站内主链,不把 JS 版本中的外围运行时逻辑迁移进来。
|
||||
|
||||
处理顺序如下:
|
||||
|
||||
1. 解析传入的 `playId`
|
||||
- 若是 JSON,读取 `page/title/origin/vodName/pic`
|
||||
- 若不是 JSON,则当作原始播放页地址
|
||||
2. 请求播放页 HTML
|
||||
3. 用正则提取 `/api/m3u8?origin=...&url=...`
|
||||
4. 请求该接口并检查响应头里的 `Location`
|
||||
- 有跳转时以跳转后的地址为候选结果
|
||||
5. 若跳转结果是 m3u8 主清单,则读取文本
|
||||
- 若存在 `/api/m3u8?id=...raw=1` 行,则拼成绝对地址并作为最终结果
|
||||
6. 若任一步失败,则返回 `parse=1`,由外部继续解析
|
||||
|
||||
播放器返回头至少包含:
|
||||
|
||||
- `User-Agent`
|
||||
- `Referer`
|
||||
- 必要时补 `Origin`
|
||||
|
||||
## 错误处理
|
||||
|
||||
- HTML 请求失败时返回空字符串,不向上抛站点异常
|
||||
- 详情页解析失败时返回空列表
|
||||
- 分类、搜索失败时返回空列表和基本分页字段
|
||||
- 播放解析失败时回退到播放页 URL 或空地址,不报未处理异常
|
||||
- 所有 helper 对缺失字段、坏 JSON、空节点、无匹配正则保持容错
|
||||
|
||||
## 测试策略
|
||||
|
||||
使用 `unittest` 与 `unittest.mock`,不走真网。
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- `homeContent` 返回 4 个分类和对应 filters
|
||||
- 卡片解析正确提取 `vod_id`、标题、图片、备注
|
||||
- `categoryContent` 正确拼装 URL 与查询参数
|
||||
- `detailContent` 正确提取元数据并组装多线路剧集
|
||||
- `searchContent` 调用搜索 URL 并执行精排
|
||||
- `playerContent` 成功提取 `/api/m3u8`
|
||||
- `playerContent` 能处理 302 跳转
|
||||
- `playerContent` 能从主清单中继续提取 `raw=1` 子清单
|
||||
- 无法提取直链时回退 `parse=1`
|
||||
|
||||
## 验收标准
|
||||
|
||||
- 新增 spider 与测试文件后,可独立运行 `tests.test_电影人生`
|
||||
- 首页、分类、搜索、详情在离线夹具下输出稳定
|
||||
- 播放支持“接口提取 -> 跳转 -> 主清单下钻 -> 失败回退”四条路径
|
||||
- 不修改共享基类即可完成接入
|
||||
Reference in New Issue
Block a user