feat: add zhizhen spider and aggregate support
This commit is contained in:
@@ -0,0 +1,170 @@
|
||||
# 玩偶聚合接入至臻设计
|
||||
|
||||
**日期:** 2026-04-20
|
||||
|
||||
## 目标
|
||||
|
||||
在现有聚合蜘蛛 [玩偶聚合.py](/home/harold/workspace/tvbox-resources/py/玩偶聚合.py) 中正式接入 `至臻` 站点,使其参与:
|
||||
|
||||
- 首页站点列表展示
|
||||
- 站点分类页抓取
|
||||
- 聚合搜索
|
||||
- 聚合详情页网盘线路合并
|
||||
|
||||
主域名固定为:
|
||||
|
||||
- `http://www.miqk.cc`
|
||||
|
||||
本次接入沿用已经确认的单站 `至臻` 解析边界:
|
||||
|
||||
- 只抓列表、搜索、详情元数据和网盘链接
|
||||
- `playerContent` 只透传网盘分享链接
|
||||
- 不做站内直链播放解析
|
||||
|
||||
## 范围
|
||||
|
||||
本次改动包含:
|
||||
|
||||
- 在 [玩偶聚合.py](/home/harold/workspace/tvbox-resources/py/玩偶聚合.py) 的 `self.sites` 中增加 `zhizhen` 配置
|
||||
- 让 `homeContent` 暴露 `site_zhizhen`
|
||||
- 让 `categoryContent` 使用 `至臻` 的分类和 URL 模板
|
||||
- 让 `searchContent` 将 `至臻` 结果纳入聚合
|
||||
- 让 `detailContent` 能合并 `至臻` 的网盘链接
|
||||
- 在 [test_玩偶聚合.py](/home/harold/workspace/tvbox-resources/py/tests/test_玩偶聚合.py) 中补充对应测试
|
||||
|
||||
本次不包含:
|
||||
|
||||
- 修改聚合 ID 编码格式
|
||||
- 抽取新的共享基类
|
||||
- 为 `至臻` 增加备用域名
|
||||
- 修改单站 [至臻.py](/home/harold/workspace/tvbox-resources/py/至臻.py) 的行为
|
||||
|
||||
## 现状
|
||||
|
||||
当前聚合蜘蛛已有:
|
||||
|
||||
- `site_priority` 中的 `zhizhen` 优先级占位
|
||||
- 通用的列表、搜索、详情和网盘线路组装逻辑
|
||||
- 站点配置驱动的 URL 构建和 XPath 解析
|
||||
|
||||
当前缺口是:
|
||||
|
||||
- `self.sites` 里还没有真正的 `zhizhen` 配置
|
||||
- 测试中也没有覆盖 `至臻` 在聚合层的展示、搜索和详情合并
|
||||
|
||||
这意味着聚合层逻辑本身基本够用,本次重点是补站点定义并用测试锁定行为。
|
||||
|
||||
## 方案选择
|
||||
|
||||
采用“最小配置接入 + 现有聚合逻辑复用”的方案。
|
||||
|
||||
具体做法:
|
||||
|
||||
- 新增一条 `zhizhen` 站点配置
|
||||
- 复用现有 `module-item`、`module-search-item`、`module-row-info` 解析流程
|
||||
- 复用现有 `_fetch_site_search`、`_parse_detail_page`、`_build_pan_lines`、`detailContent` 合并逻辑
|
||||
|
||||
不采用“让聚合层调用单站 `至臻.py`”的方案,原因是:
|
||||
|
||||
- 当前聚合蜘蛛的结构是配置驱动,不是子 Spider 组合
|
||||
- 强行调用单站 Spider 会把接口耦合变复杂
|
||||
- 本次站点结构与现有聚合模板兼容,没有必要新增调度层
|
||||
|
||||
## 站点配置设计
|
||||
|
||||
新增站点项字段:
|
||||
|
||||
- `id`: `zhizhen`
|
||||
- `name`: `至臻`
|
||||
- `domains`: `["http://www.miqk.cc"]`
|
||||
- `filter_files`: `[]`
|
||||
- `list_xpath`: `//*[contains(@class,'module-item')]`
|
||||
- `search_xpath`: `//*[contains(@class,'module-search-item')]`
|
||||
- `detail_pan_xpath`: `//*[contains(@class,'module-row-info')]//p`
|
||||
- `category_url`: `/index.php/vod/show/id/{categoryId}/page/{page}.html`
|
||||
- `search_url`: `/index.php/vod/search/page/{page}/wd/{keyword}.html`
|
||||
- `default_categories`: `[("1","电影"),("2","剧集"),("3","动漫"),("4","综艺"),("5","短剧"),("24","老剧"),("26","严选")]`
|
||||
|
||||
这里不配置 `category_url_with_filters`,因为用户给出的 `至臻` 参考实现只确认了基础分类翻页 URL,没有额外筛选规则。
|
||||
|
||||
## 行为设计
|
||||
|
||||
### 首页
|
||||
|
||||
`homeContent` 应新增一项:
|
||||
|
||||
- `type_id = site_zhizhen`
|
||||
- `type_name = 至臻`
|
||||
|
||||
`filters["site_zhizhen"]` 中的第一个筛选组应为 `categoryId`,值列表映射到 `至臻` 的 7 个默认分类。
|
||||
|
||||
### 分类页
|
||||
|
||||
`categoryContent("site_zhizhen", pg, ..., extend)` 应:
|
||||
|
||||
- 从 `extend["categoryId"]` 读取分类
|
||||
- 若未提供,则默认使用 `1`
|
||||
- 构建 `http://www.miqk.cc/index.php/vod/show/id/<categoryId>/page/<pg>.html`
|
||||
- 按现有通用列表解析逻辑输出站内条目
|
||||
|
||||
返回结构保持与现有聚合站一致:
|
||||
|
||||
- `vod_id` 使用 `site:zhizhen:<detail_path>`
|
||||
- 保留 `_site` 和 `_detail_path`
|
||||
- 不返回 `pagecount`
|
||||
|
||||
### 搜索
|
||||
|
||||
`searchContent` 不改接口,只需要确保:
|
||||
|
||||
- `_fetch_site_search` 能对 `zhizhen` 使用其 `search_url`
|
||||
- 结果进入 `_aggregate_search_results`
|
||||
- 若同名同年命中多个站点,仍按 `site_priority` 决定主信息来源
|
||||
|
||||
因为 `site_priority` 中 `zhizhen` 已排在 `labi` 后、`erxiao` 前,本次不调整站点优先级。
|
||||
|
||||
### 详情
|
||||
|
||||
聚合详情和单站详情都不改数据模型,只要 `zhizhen` 配置加入后能被现有流程消费。
|
||||
|
||||
重点保证:
|
||||
|
||||
- `_fetch_site_detail` 能按 `site["domains"][0] + path` 请求 `至臻` 详情页
|
||||
- `_parse_detail_page` 可用通用 `.page-title` / `.mobile-play` / `.video-info-itemtitle` / `detail_pan_xpath` 提取字段
|
||||
- `detailContent` 合并 `至臻` 的网盘线路时遵守现有去重和排序规则
|
||||
|
||||
## 测试设计
|
||||
|
||||
本次至少新增以下测试:
|
||||
|
||||
1. 首页暴露 `site_zhizhen`
|
||||
- 校验 `homeContent(False)["class"]` 中包含 `site_zhizhen`
|
||||
- 校验 `filters["site_zhizhen"]` 的分类项包含 `1/2/3/4/5/24/26`
|
||||
|
||||
2. `至臻` 搜索 URL 构造与解析
|
||||
- 构造一个 `zhizhen` 站点配置
|
||||
- mock `_request_with_failover`
|
||||
- 断言 `_fetch_site_search` 请求 `http://www.miqk.cc/index.php/vod/search/page/1/wd/<keyword>.html`
|
||||
- 断言结果被编码为 `site:zhizhen:<path>`
|
||||
|
||||
3. 聚合详情合并 `至臻` 网盘线路
|
||||
- mock `_fetch_site_detail`,让一个聚合 payload 同时包含例如 `wanou` 和 `zhizhen`
|
||||
- 断言 `vod_play_from` / `vod_play_url` 中含 `#至臻` 的线路
|
||||
- 断言重复链接仍会按现有规则去重
|
||||
|
||||
必要时再补一个分类页测试,锁定 `site_zhizhen` 的分类 URL 模板。
|
||||
|
||||
## 风险
|
||||
|
||||
- `至臻` 的分类 URL 与现有 `/vodshow/...` 模板不同,若直接沿用旧模板会导致站点在聚合层无法访问分类页
|
||||
- `default_categories` 若错误复用其他站的 `29` 或 `21` 等 ID,会让筛选项和真实站点不一致
|
||||
- 若测试只验证首页展示、不验证搜索和详情,则很容易出现“站点名显示了,但实际不可用”的假集成
|
||||
|
||||
## 验收标准
|
||||
|
||||
满足以下条件即可认为完成:
|
||||
|
||||
- [玩偶聚合.py](/home/harold/workspace/tvbox-resources/py/玩偶聚合.py) 的 `self.sites` 中新增 `zhizhen` 配置
|
||||
- [test_玩偶聚合.py](/home/harold/workspace/tvbox-resources/py/tests/test_玩偶聚合.py) 覆盖 `至臻` 的首页、搜索或详情至少三类行为
|
||||
- `python -m unittest tests.test_玩偶聚合 -v` 通过
|
||||
- 聚合层返回结构不引入新的字段格式变化
|
||||
@@ -0,0 +1,291 @@
|
||||
# 至臻 Python 爬虫设计
|
||||
|
||||
**日期:** 2026-04-20
|
||||
|
||||
## 目标
|
||||
|
||||
在当前 Python Spider 仓库中新增一个独立单站蜘蛛 `至臻.py`,参考用户提供的 JS 版本行为,实现符合 `base.spider.Spider` 接口的网盘资源站适配。
|
||||
|
||||
本次实现需要覆盖:
|
||||
|
||||
- 固定 7 个分类
|
||||
- 分类列表
|
||||
- 搜索
|
||||
- 详情页元数据解析
|
||||
- 网盘链接整理
|
||||
- 播放透传
|
||||
- 对应 `unittest`
|
||||
|
||||
## 范围
|
||||
|
||||
本次实现包含:
|
||||
|
||||
- 新增独立蜘蛛文件 `py/至臻.py`
|
||||
- 新增测试文件 `py/tests/test_至臻.py`
|
||||
- 单域名站点适配:`http://www.miqk.cc`
|
||||
- 固定 7 个分类,分类 ID 与参考 JS 保持一致
|
||||
- 分类页和搜索页卡片解析
|
||||
- 详情页元数据与网盘链接提取
|
||||
- 按网盘类型输出 `vod_play_from` 和 `vod_play_url`
|
||||
- `playerContent` 对已识别网盘分享链接直接透传
|
||||
|
||||
本次实现不包含:
|
||||
|
||||
- 聚合多站
|
||||
- 站内直链播放解析
|
||||
- 本地筛选配置文件
|
||||
- 验证码、浏览器执行或复杂反爬绕过
|
||||
- 修改 `base/` 公共层
|
||||
|
||||
## 方案选择
|
||||
|
||||
采用“单站单文件 + 少量 helper + 单测”的仓库现有模式,而不是直接保存用户提供的 JS 代码。
|
||||
|
||||
原因:
|
||||
|
||||
- 用户已确认以独立单站爬虫交付
|
||||
- 当前仓库已存在多个相同结构的单文件 Spider
|
||||
- 私有 helper 能把 URL 组装、文本清洗、卡片解析、详情提取和网盘识别拆开,便于后续修站
|
||||
- 解析逻辑可以通过静态 HTML 单测稳定覆盖,不依赖真实网络
|
||||
|
||||
不采用“提前抽公共盘站基类”的方案,因为本次目标是尽快落一个站点,过早抽象会扩大改动面。
|
||||
|
||||
## 接口设计
|
||||
|
||||
### `homeContent`
|
||||
|
||||
返回固定 7 个分类:
|
||||
|
||||
- `1 -> 至臻电影`
|
||||
- `2 -> 至臻剧集`
|
||||
- `3 -> 至臻动漫`
|
||||
- `4 -> 至臻综艺`
|
||||
- `5 -> 至臻短剧`
|
||||
- `24 -> 至臻老剧`
|
||||
- `26 -> 至臻严选`
|
||||
|
||||
不返回筛选项。
|
||||
|
||||
### `homeVideoContent`
|
||||
|
||||
返回空列表:
|
||||
|
||||
- `{"list": []}`
|
||||
|
||||
### `categoryContent`
|
||||
|
||||
分类页 URL 规则:
|
||||
|
||||
- `/index.php/vod/show/id/{tid}/page/{page}.html`
|
||||
|
||||
解析 `#main .module-item` 卡片并输出:
|
||||
|
||||
- `vod_id`
|
||||
- `vod_name`
|
||||
- `vod_pic`
|
||||
- `vod_remarks`
|
||||
- `vod_year`
|
||||
|
||||
分页返回字段:
|
||||
|
||||
- `page`
|
||||
- `limit`
|
||||
- `total`
|
||||
- `list`
|
||||
|
||||
不返回 `pagecount`。
|
||||
|
||||
### `searchContent`
|
||||
|
||||
搜索 URL 规则:
|
||||
|
||||
- `/index.php/vod/search/page/{page}/wd/{keyword}.html`
|
||||
|
||||
空关键词直接返回空列表。
|
||||
|
||||
搜索结果结构与分类列表保持一致,但 `vod_remarks` 优先取 `.video-serial` 文本。
|
||||
|
||||
### `detailContent`
|
||||
|
||||
通过详情页提取:
|
||||
|
||||
- `vod_id`
|
||||
- `vod_name`
|
||||
- `vod_pic`
|
||||
- `vod_year`
|
||||
- `vod_director`
|
||||
- `vod_actor`
|
||||
- `vod_content`
|
||||
- `vod_play_from`
|
||||
- `vod_play_url`
|
||||
|
||||
详情页只整理网盘分享链接,不解析站内播放器。
|
||||
|
||||
### `playerContent`
|
||||
|
||||
若 `id` 是支持的网盘分享链接,则返回透传结果:
|
||||
|
||||
```python
|
||||
{"parse": 0, "playUrl": "", "url": id}
|
||||
```
|
||||
|
||||
若不是已识别网盘链接,则返回空 URL:
|
||||
|
||||
```python
|
||||
{"parse": 0, "playUrl": "", "url": ""}
|
||||
```
|
||||
|
||||
## 模块边界
|
||||
|
||||
新蜘蛛内部拆分为以下职责:
|
||||
|
||||
- 站点配置与固定分类
|
||||
- URL 组装
|
||||
- 文本清洗
|
||||
- HTML 请求封装
|
||||
- 列表卡片解析
|
||||
- 搜索结果解析
|
||||
- 详情页字段提取
|
||||
- 网盘类型识别
|
||||
- 网盘线路拼接
|
||||
|
||||
不新增公共基类,不抽共享模块。
|
||||
|
||||
## URL 与 ID 设计
|
||||
|
||||
详情页 `vod_id` 使用站内短路径,而不是完整 URL。
|
||||
|
||||
编码方式:
|
||||
|
||||
- 详情链接 `/index.php/vod/detail/id/123.html` 对外直接保存为 `/index.php/vod/detail/id/123.html`
|
||||
|
||||
原因:
|
||||
|
||||
- 与用户给出的 JS 行为一致
|
||||
- 当前仓库已有多个蜘蛛直接使用站内短路径作为 `vod_id`
|
||||
- 单站实现不需要额外编码层
|
||||
|
||||
详情请求时再基于主域拼成完整地址。
|
||||
|
||||
## 请求策略
|
||||
|
||||
主域固定为:
|
||||
|
||||
- `http://www.miqk.cc`
|
||||
|
||||
请求头包含固定 `User-Agent` 和首页 `Referer`。
|
||||
|
||||
异常处理策略:
|
||||
|
||||
- 页面请求失败时返回空列表或空字段结果
|
||||
- 不向上抛出未处理异常
|
||||
- 不实现多域名切换
|
||||
- 不实现重试
|
||||
|
||||
## 列表与搜索解析
|
||||
|
||||
分类列表解析容器:
|
||||
|
||||
- `#main .module-item`
|
||||
|
||||
提取策略:
|
||||
|
||||
- 链接:`.module-item-pic a[href]`
|
||||
- 标题:`.module-item-pic img[alt]`
|
||||
- 封面:`.module-item-pic img[data-src|src]`
|
||||
- 备注:`.module-item-text`
|
||||
- 年份:`.module-item-caption span:first-child`
|
||||
|
||||
搜索结果解析容器:
|
||||
|
||||
- `.module-search-item`
|
||||
|
||||
提取策略:
|
||||
|
||||
- 链接和标题优先来自 `.video-serial`
|
||||
- 封面来自 `.module-item-pic img[data-src|src]`
|
||||
- 备注优先取 `.video-serial` 文本,缺失时回退 `.module-item-text`
|
||||
|
||||
列表和搜索都应忽略空标题或空链接项。
|
||||
|
||||
## 详情解析
|
||||
|
||||
详情页字段来源按用户提供的 JS 保持一致:
|
||||
|
||||
- 标题:`.page-title`
|
||||
- 封面:`.mobile-play .lazyload[data-src|src]`
|
||||
- 标注区:`.video-info-itemtitle` 与其相邻节点
|
||||
- 网盘链接:`.module-row-info p`
|
||||
|
||||
字段映射规则:
|
||||
|
||||
- `年代` -> `vod_year`
|
||||
- `导演` -> `vod_director`
|
||||
- `主演` -> `vod_actor`
|
||||
- `剧情` -> `vod_content`
|
||||
|
||||
其中导演、主演优先拼接相邻区域中的链接文本;剧情提取文本内容并做空白清洗。
|
||||
|
||||
## 网盘线路整理
|
||||
|
||||
支持识别以下网盘:
|
||||
|
||||
- 百度
|
||||
- 139
|
||||
- 天翼
|
||||
- 123
|
||||
- 115
|
||||
- 夸克
|
||||
- 迅雷
|
||||
- 阿里
|
||||
- UC
|
||||
|
||||
排序优先级:
|
||||
|
||||
1. 百度
|
||||
2. 139
|
||||
3. 天翼
|
||||
4. 123
|
||||
5. 115
|
||||
6. 夸克
|
||||
7. 迅雷
|
||||
8. 阿里
|
||||
9. UC
|
||||
|
||||
输出规则:
|
||||
|
||||
- `vod_play_from` 使用 `{pan_type}#至臻` 线路名拼接
|
||||
- `vod_play_url` 使用 `{标题}${分享链接}` 拼接
|
||||
- 不支持的链接忽略
|
||||
- 重复链接去重
|
||||
|
||||
## 测试策略
|
||||
|
||||
采用 `unittest` 和 `unittest.mock`,不依赖真实网络。
|
||||
|
||||
至少覆盖:
|
||||
|
||||
- 固定分类和空首页
|
||||
- URL 构建与网盘识别
|
||||
- 分类卡片解析
|
||||
- 分类接口 URL 拼装
|
||||
- 搜索接口 URL 拼装和结果解析
|
||||
- 详情元数据提取
|
||||
- 网盘线路去重和排序
|
||||
- `detailContent` 最终输出
|
||||
- `playerContent` 对网盘链接透传和非网盘拒绝
|
||||
|
||||
## 风险与约束
|
||||
|
||||
- 站点 DOM 如果与用户提供的 JS 片段不一致,测试需要以当前仓库约定的静态夹具为准
|
||||
- 搜索关键词直接拼接到路径中,需做 URL 编码
|
||||
- 详情页相邻节点结构若出现空白文本节点,解析时需要回退到 XPath 文本合并,避免取值为空
|
||||
|
||||
## 验收标准
|
||||
|
||||
满足以下条件即可认为完成:
|
||||
|
||||
- `py/至臻.py` 实现 `Spider` 所需接口
|
||||
- `py/tests/test_至臻.py` 覆盖核心行为
|
||||
- 针对 `至臻` 模块的单测全部通过
|
||||
- 返回结构与当前仓库同类盘站蜘蛛保持一致
|
||||
Reference in New Issue
Block a user