docs: add wanou aggregate spider design
This commit is contained in:
@@ -0,0 +1,429 @@
|
||||
# 玩偶聚合 Spider 设计
|
||||
|
||||
**日期:** 2026-04-20
|
||||
|
||||
## 目标
|
||||
|
||||
在当前 `py/` Spider 仓库中新增一个“玩偶聚合”源,提供以下能力:
|
||||
|
||||
- 以站点为一级分类展示聚合站。
|
||||
- 每个站点在分类页内继续使用原站分类和筛选项。
|
||||
- 搜索时并发请求多个站点,并将同片结果聚合为单条记录。
|
||||
- 聚合详情页合并多个站点的网盘分享线路。
|
||||
- `playerContent` 不展开网盘剧集,只透传分享链接。
|
||||
|
||||
明确不做:
|
||||
|
||||
- 独立管理后台。
|
||||
- 监控页面。
|
||||
- 常驻定时域名巡检任务。
|
||||
- 在 Spider 内调用网盘驱动展开剧集列表。
|
||||
|
||||
## 现状与约束
|
||||
|
||||
当前仓库是单文件 Python Spider 集合,统一继承 `base/spider.py` 中的 `Spider` 基类,测试使用 `unittest` 和 `unittest.mock`。现有仓库已接受以下模式:
|
||||
|
||||
- `homeContent` 返回 `class` 和可选 `filters`。
|
||||
- `categoryContent` 使用 `extend` 解析筛选参数。
|
||||
- `detailContent` 可以返回网盘分享链接组成的 `vod_play_from` / `vod_play_url`。
|
||||
- `playerContent` 可以对网盘链接做原样透传。
|
||||
- 返回列表结果时不包含 `pagecount`。
|
||||
|
||||
因此,新 Spider 必须遵守当前仓库接口和测试风格,而不是照搬原始 Node/Fastify 插件结构。
|
||||
|
||||
## 方案选择
|
||||
|
||||
采用“配置驱动的单 Spider 聚合层”方案:
|
||||
|
||||
- 新增单文件 `玩偶聚合.py`。
|
||||
- 文件内部包含站点配置、通用抓取逻辑、聚合编排逻辑。
|
||||
- 对差异较大的站点保留少量站点钩子,避免把所有逻辑写成纯硬编码分支。
|
||||
|
||||
不采用“每站点一个适配器文件”的方案,原因是当前仓库以单文件 Spider 为主,这种拆分会引入额外组织成本;也不采用“全部 if/else 硬编码”的方案,原因是后续修站难度会快速上升。
|
||||
|
||||
## 模块职责
|
||||
|
||||
`玩偶聚合.py` 内部拆成三层职责:
|
||||
|
||||
### 1. 站点配置层
|
||||
|
||||
维护聚合站点定义,包括:
|
||||
|
||||
- 站点 ID 和中文名。
|
||||
- 域名列表,按优先顺序排列。
|
||||
- 分类 URL 模板。
|
||||
- 搜索 URL 模板。
|
||||
- 列表、搜索、详情解析用选择器或 XPath 规则。
|
||||
- 原站默认分类。
|
||||
- 可选的本地筛选配置文件映射。
|
||||
- 站点优先级。
|
||||
|
||||
### 2. 通用采集层
|
||||
|
||||
负责:
|
||||
|
||||
- 请求 HTML。
|
||||
- 域名失败切换。
|
||||
- 列表卡片解析。
|
||||
- 搜索卡片解析。
|
||||
- 详情页元数据提取。
|
||||
- 网盘分享链接识别与分组。
|
||||
- 聚合 ID 编解码辅助。
|
||||
|
||||
### 3. 聚合编排层
|
||||
|
||||
负责:
|
||||
|
||||
- 首页按站点输出分类和筛选结构。
|
||||
- 分类请求路由到指定站点。
|
||||
- 搜索并发拉取多站结果。
|
||||
- 基于名称和年份做结果聚合。
|
||||
- 聚合详情拉取多站详情并合并线路。
|
||||
- `playerContent` 透传网盘链接。
|
||||
|
||||
## Spider 对外行为
|
||||
|
||||
### homeContent
|
||||
|
||||
首页使用“站点优先”模式:
|
||||
|
||||
- `class` 中每个条目代表一个聚合站点。
|
||||
- `type_id` 使用 `site_<site_id>` 格式。
|
||||
- `type_name` 使用站点中文名。
|
||||
|
||||
每个站点的 `filters` 至少包含:
|
||||
|
||||
- `categoryId` 分组,对应原站分类。
|
||||
|
||||
若该站有可落地的本地筛选配置,则继续追加该站支持的:
|
||||
|
||||
- `area`
|
||||
- `year`
|
||||
- `class`
|
||||
- `by` 或 `sort`
|
||||
- 其他与模板兼容的筛选字段
|
||||
|
||||
这样,使用方在 UI 上会先选站点,再选该站原始分类和筛选项。
|
||||
|
||||
### categoryContent
|
||||
|
||||
`tid` 必须是 `site_<site_id>`。
|
||||
|
||||
处理逻辑:
|
||||
|
||||
1. 从 `tid` 提取目标站点。
|
||||
2. 从 `extend` 中读取 `categoryId`。
|
||||
3. 读取该站支持的附加筛选项。
|
||||
4. 按该站模板拼分类 URL。
|
||||
5. 请求 HTML,解析列表卡片。
|
||||
6. 返回当前页结果。
|
||||
|
||||
当 `extend` 未提供 `categoryId` 时,默认使用该站首个分类。
|
||||
|
||||
### searchContent
|
||||
|
||||
搜索默认启用聚合模式:
|
||||
|
||||
1. 对所有站点并发发起搜索请求。
|
||||
2. 每个站点单独设置超时,超时只影响该站。
|
||||
3. 解析得到站内搜索卡片列表。
|
||||
4. 基于名称归一化和年份辅助规则进行跨站聚合。
|
||||
5. 选择优先级最高的站点结果作为聚合主信息。
|
||||
6. 生成聚合 `vod_id` 并返回聚合后的列表。
|
||||
|
||||
聚合结果默认不再把同片不同站拆成多条返回。
|
||||
|
||||
### detailContent
|
||||
|
||||
支持两类 ID:
|
||||
|
||||
- 单站详情 ID。
|
||||
- 聚合详情 ID。
|
||||
|
||||
单站详情:
|
||||
|
||||
- 请求对应站点详情页。
|
||||
- 提取片名、海报、年份、导演、演员、简介。
|
||||
- 提取并识别所有网盘分享链接。
|
||||
- 生成 `vod_play_from` 和 `vod_play_url`。
|
||||
|
||||
聚合详情:
|
||||
|
||||
- 解码聚合 ID 中包含的站点条目。
|
||||
- 按站点优先级依次请求多个站点详情。
|
||||
- 跳过失败站点和无网盘站点。
|
||||
- 合并多个站点的网盘线路并输出。
|
||||
|
||||
详情页不展开网盘剧集,不调用外部盘驱动。
|
||||
|
||||
### playerContent
|
||||
|
||||
仅负责透传常见网盘分享链接。
|
||||
|
||||
支持:
|
||||
|
||||
- `pan.baidu.com`
|
||||
- `pan.quark.cn`
|
||||
- `drive.uc.cn`
|
||||
- `alipan.com`
|
||||
- `aliyundrive.com`
|
||||
- `pan.xunlei.com`
|
||||
- `115.com`
|
||||
- `123pan.com`
|
||||
- `cloud.189.cn` 或等价天翼域名
|
||||
- `yun.139.com` 或等价移动云盘域名
|
||||
|
||||
当 `flag` 或 `id` 能识别为上述网盘分享链接时,返回:
|
||||
|
||||
```python
|
||||
{"parse": 0, "playUrl": "", "url": "<share-url>"}
|
||||
```
|
||||
|
||||
无法识别时返回空 URL,不尝试站内播放页解析。
|
||||
|
||||
## 数据模型设计
|
||||
|
||||
### 单站结果 ID
|
||||
|
||||
分类页中的普通条目使用:
|
||||
|
||||
`site:<site_id>:<detail_path>`
|
||||
|
||||
示例:
|
||||
|
||||
`site:wanou:/voddetail/12345.html`
|
||||
|
||||
要求:
|
||||
|
||||
- 保留站点信息。
|
||||
- 保留足够重建详情 URL 的短路径。
|
||||
- 不直接存储整页 HTML 或冗长 JSON。
|
||||
|
||||
### 聚合结果 ID
|
||||
|
||||
搜索聚合结果使用:
|
||||
|
||||
`agg:<base64_json>`
|
||||
|
||||
JSON 负载为条目数组,每个条目至少包含:
|
||||
|
||||
- `site`
|
||||
- `path`
|
||||
- `name`
|
||||
- `year`
|
||||
|
||||
这样可以:
|
||||
|
||||
- 避免把多个站点路径用裸字符串硬拼到 `vod_id` 里。
|
||||
- 在详情阶段稳定恢复参与聚合的站点列表。
|
||||
- 控制 `vod_id` 长度和结构清晰度。
|
||||
|
||||
### 播放线路
|
||||
|
||||
`vod_play_from` 使用盘类型加来源站点命名,例如:
|
||||
|
||||
- `baidu#玩偶`
|
||||
- `quark#木偶`
|
||||
- `a123#蜡笔`
|
||||
|
||||
`vod_play_url` 直接存分享链接:
|
||||
|
||||
- `百度合集$https://pan.baidu.com/s/...`
|
||||
- `夸克资源$https://pan.quark.cn/s/...`
|
||||
|
||||
同类型多站资源允许并存,以来源站区分。
|
||||
|
||||
## 搜索聚合规则
|
||||
|
||||
### 名称归一化
|
||||
|
||||
对片名做规范化,用于跨站聚合判断:
|
||||
|
||||
- 转小写。
|
||||
- 去除空白和常见标点。
|
||||
- 去除常见分辨率或来源尾巴,如 `4K`、`HDR`、`2160P`、`1080P`。
|
||||
- 去除常见站点附加标签。
|
||||
|
||||
### 聚合判定
|
||||
|
||||
优先使用以下规则:
|
||||
|
||||
1. 归一化片名完全相同,可聚合。
|
||||
2. 若双方年份都存在且不相同,则不能聚合。
|
||||
3. 若年份一致或其中一方缺失年份,允许聚合。
|
||||
4. 对明显不同的片名,即使部分包含,也不强行聚合。
|
||||
|
||||
本次实现不引入复杂模糊匹配算法,避免误合并;先用保守规则建立稳定版本。
|
||||
|
||||
### 主信息来源
|
||||
|
||||
聚合组内按站点优先级排序,优先级最高的记录决定:
|
||||
|
||||
- `vod_name`
|
||||
- `vod_pic`
|
||||
- `vod_remarks`
|
||||
- `vod_year`
|
||||
|
||||
同时保留来源标签供详情阶段使用。
|
||||
|
||||
## 详情聚合规则
|
||||
|
||||
### 单站详情解析
|
||||
|
||||
每个站点详情页尽量提取:
|
||||
|
||||
- 标题
|
||||
- 海报
|
||||
- 年份
|
||||
- 地区
|
||||
- 类型
|
||||
- 导演
|
||||
- 演员
|
||||
- 简介
|
||||
- 网盘分享链接
|
||||
|
||||
如果该站只有网盘资源,没有站内剧集线路,也视为有效站点。
|
||||
|
||||
### 网盘识别
|
||||
|
||||
根据链接域名识别盘类型,优先以分享域名为准,而不是文案标签:
|
||||
|
||||
- 百度
|
||||
- 夸克
|
||||
- UC
|
||||
- 阿里
|
||||
- 迅雷
|
||||
- 115
|
||||
- 123
|
||||
- 天翼
|
||||
- 移动云盘
|
||||
|
||||
### 合并策略
|
||||
|
||||
聚合详情按站点优先级遍历多站结果:
|
||||
|
||||
- 失败站点直接跳过。
|
||||
- 无网盘链接的站点直接跳过。
|
||||
- 同一站内重复链接去重。
|
||||
- 同一分享链接跨站重复时只保留一份。
|
||||
- `vod_play_from` 顺序先按盘优先级,再按站点优先级。
|
||||
|
||||
主详情信息取第一个成功站点。
|
||||
|
||||
如果所有站点都没有可用网盘链接,则返回空播放线路。
|
||||
|
||||
## 域名容错
|
||||
|
||||
不做后台监控,只做请求时故障切换。
|
||||
|
||||
每个站点维护多个候选域名:
|
||||
|
||||
1. 请求时按当前顺序逐个尝试。
|
||||
2. 某个域名成功后,将其提升到列表前部。
|
||||
3. 失败时继续尝试下一个域名。
|
||||
4. 全部失败则该站本次请求记为空结果或详情失败。
|
||||
|
||||
该策略适用于:
|
||||
|
||||
- 分类页。
|
||||
- 搜索页。
|
||||
- 详情页。
|
||||
|
||||
不会引入线程、定时器或额外 HTTP 管理接口。
|
||||
|
||||
## 站点筛选策略
|
||||
|
||||
优先从仓库本地配置文件加载可用筛选项;若某站缺少本地筛选配置,则仅提供:
|
||||
|
||||
- 分类 `categoryId`
|
||||
|
||||
分类分组必须按用户配置顺序输出,避免被 Python 字典顺序或后处理逻辑打乱。
|
||||
|
||||
对于筛选 URL,支持两种模式:
|
||||
|
||||
- 站点自定义模板。
|
||||
- 通用 CMS 模板回退。
|
||||
|
||||
## 测试设计
|
||||
|
||||
为新 Spider 新增 `tests/test_玩偶聚合.py`,覆盖三层行为。
|
||||
|
||||
### 1. 纯函数与辅助方法
|
||||
|
||||
- 站点 ID 解析。
|
||||
- 单站 `vod_id` 编解码。
|
||||
- 聚合 `vod_id` 编解码。
|
||||
- 片名归一化。
|
||||
- 聚合判定规则。
|
||||
- 网盘类型识别。
|
||||
|
||||
### 2. 单站解析与 URL 构建
|
||||
|
||||
- `homeContent` 输出站点分类和筛选结构。
|
||||
- 分类 URL 根据 `extend` 正确拼接。
|
||||
- 搜索 URL 根据关键字正确构建。
|
||||
- 单站列表卡片正确解析。
|
||||
- 单站详情正确抽取网盘链接。
|
||||
- 域名切换在首域失败后能使用备用域。
|
||||
|
||||
### 3. 聚合行为
|
||||
|
||||
- 多站搜索结果合并为单条。
|
||||
- 年份冲突结果不合并。
|
||||
- 聚合详情合并多个站点线路。
|
||||
- 聚合详情对重复分享链接去重。
|
||||
- `playerContent` 透传 quark / baidu / uc / aliyun / xunlei 等常见盘链接。
|
||||
|
||||
所有测试使用内嵌 HTML 或 mock response,不访问真实网络。
|
||||
|
||||
## 文件变更计划
|
||||
|
||||
预计后续实现阶段将修改或新增:
|
||||
|
||||
- 新增 `py/玩偶聚合.py`
|
||||
- 新增 `py/tests/test_玩偶聚合.py`
|
||||
- 如有必要,新增本地筛选配置文件,但优先复用已有 `筛选` 目录资源
|
||||
|
||||
本设计阶段只新增本 spec 文件。
|
||||
|
||||
## 风险与处理
|
||||
|
||||
### 1. 站点结构不完全一致
|
||||
|
||||
处理方式:
|
||||
|
||||
- 使用站点配置驱动。
|
||||
- 仅为少量差异保留钩子函数。
|
||||
|
||||
### 2. 搜索误聚合
|
||||
|
||||
处理方式:
|
||||
|
||||
- 初版采用保守聚合规则。
|
||||
- 以完全归一化片名匹配为主,年份冲突即拆开。
|
||||
|
||||
### 3. 聚合 ID 过长
|
||||
|
||||
处理方式:
|
||||
|
||||
- 使用精简 JSON 负载。
|
||||
- 仅保存详情恢复必需字段。
|
||||
|
||||
### 4. 备用域名经常失效
|
||||
|
||||
处理方式:
|
||||
|
||||
- 保持请求时故障切换。
|
||||
- 不引入复杂监控模块。
|
||||
|
||||
## 实施结论
|
||||
|
||||
后续实现应严格围绕以下范围展开:
|
||||
|
||||
- Python 单文件聚合 Spider。
|
||||
- 站点优先首页结构。
|
||||
- 搜索默认聚合。
|
||||
- 详情合并网盘分享线路。
|
||||
- `playerContent` 只透传分享链接。
|
||||
|
||||
超出上述范围的监控后台、定时巡检、管理 API 和网盘剧集展开,均不在本次任务中。
|
||||
Reference in New Issue
Block a user