Files
tvboxzt/py/docs/superpowers/specs/2026-04-19-ddys-spider-design.md
T
2026-04-19 16:32:28 +08:00

7.9 KiB

低端影视 Python 爬虫设计

目标

在当前 Python 仓库中新增一个符合 base.spider.Spider 接口的低端影视站点爬虫,覆盖以下能力:

  • 首页分类与筛选
  • 分类列表
  • 搜索
  • 详情解析
  • 播放解析

实现基于站点 HTML 页面结构,不引入服务端路由层,不修改 base/ 公共层,并且保留详情页中的网盘分享链接。

范围

本次实现包含:

  • 新增独立脚本,文件名为 低端影视.py
  • 使用单一站点主域:https://ddys.io
  • 支持 home/category/detail/search/player 主链路
  • 首页返回固定分类与静态筛选配置
  • 详情页同时输出站内播放线路和网盘分享线路
  • playerContent 对站内线路返回直链,对网盘线路直接透传分享链接

本次实现不包含:

  • 参考 JS 中的 Fastify 路由封装
  • 网盘驱动匹配、网盘二次解析、网盘播放鉴权
  • 浏览器自动化或 JS 执行环境
  • 多域名探活与自动切换
  • 登录态、Cookie 常驻维护、站点反爬绕过

方案选择

采用仓库现有的“单站点单文件 + 单测”方案:

  • 对外保持 Spider 接口兼容
  • 对内拆分为请求封装、列表解析、详情解析、播放器提取几个 helper
  • 保留参考实现的核心行为,但只实现当前 Python 仓库真正需要的 Spider 逻辑

不直接照搬参考 JS 服务端包装层的原因是:

  • 当前仓库只消费 Spider 接口,不消费站内 HTTP API
  • Python 版已有成熟模式,新增站点应遵循既有结构
  • 这次重点是 HTML 解析与数据整形,不是路由或中间件封装

模块边界

新增脚本只在站点文件内部维护逻辑,不修改 base/

脚本内部职责拆分如下:

  • init
    • 初始化主域、请求头、固定分类、筛选项与分页参数
  • homeContent
    • 返回固定 classfilters
  • homeVideoContent
    • 返回空列表,不额外做首页推荐抓取
  • categoryContent
    • 根据分类、筛选和分页拼出 URL,请求 HTML 并解析卡片
  • detailContent
    • 请求详情页,提取影片元数据、普通播放线路和网盘线路
  • searchContent
    • 通过站内搜索接口 POST 关键词并解析结果卡片
  • playerContent
    • 对普通线路返回最终 URL,对网盘线路直接返回分享链接
  • 私有辅助函数
    • 补全相对地址
    • 清理文本
    • 模板化分类筛选路径
    • 解析卡片列表
    • 解析详情元信息
    • 解析普通播放源
    • 解析并保留网盘分享链接

Host 与请求策略

本次只实现单域:

  • https://ddys.io

请求统一通过 self.fetch / self.post 发起,固定请求头至少包含:

  • User-Agent
  • Referer

搜索接口额外补充:

  • Content-Type: application/x-www-form-urlencoded

请求原则:

  • HTML 请求超时固定为 10 秒
  • 请求失败时返回空 HTML 或空结果,不抛出未处理异常
  • 不引入 gzip/base64 之外的额外协议适配

分类与筛选设计

首页分类固定为:

  • series -> 剧集
  • movie -> 电影
  • variety -> 综艺
  • anime -> 动漫

筛选配置直接内置到脚本中,字段与参考实现保持一致:

  • class
  • area
  • year
  • by

筛选 URL 规则采用模板拼接:

  • {{fl.by}}{{fl.cateId}}{{fl.class}}{{fl.area}}{{fl.year}}/page/fypage

规则说明:

  • cateId 来自当前分类默认配置
  • class/area/year/by 来自传入的 extend
  • 当第一页且存在可选分页模板时,输出第一页真实路径
  • 当页无结果时返回当前页,避免上层无限翻页

homeContent 返回:

  • class
  • filters

不返回首页推荐列表。

列表与搜索设计

分类页解析对象为新版卡片:

  • 外层选择器:.movie-card
  • 标题:h3
  • 图片:img[src]
  • 备注:.poster-badge
  • 链接:内部 a[href]

输出统一卡片结构:

  • vod_id
  • vod_name
  • vod_pic
  • vod_remarks

搜索接口使用:

  • POST /search

请求体:

  • q=<关键词>

搜索结果优先解析第一个结果区块中的 .movie-card,如果站点结构缺失,再回退到通用卡片解析器。

分页策略采用保守估计:

  • 分类页 limit 固定为 24
  • 当页有结果时,pagecount = page + 1
  • 当页无结果时,pagecount = page
  • 搜索同样按“有结果则可翻下一页”的保守逻辑返回

详情页设计

详情页仅适配新版页面结构。

元信息提取范围:

  • 标题:主标题与可选副标题
  • 封面:首张主海报图
  • 年份、地区、类型
  • 导演、主演
  • 剧情简介

详情输出字段至少包含:

  • vod_id
  • vod_name
  • vod_pic
  • vod_content
  • vod_remarks
  • vod_year
  • vod_area
  • vod_class
  • vod_director
  • vod_actor
  • vod_play_from
  • vod_play_url

播放来源分为两组:

  1. 普通站内线路
    • 来自页面中的 switchSource(...) 按钮
    • 线路名使用按钮文本
    • 单线路只有一个 URL 时输出 全集$<url>
    • 多集线路按 名称$URL#名称$URL 组织
  2. 网盘线路
    • 来自 .download-type-content 模块中的按钮
    • atob('...') 中解码出真实分享链接
    • 每个支持的网盘分组单独作为一条线路

网盘线路识别范围:

  • quark
  • xunlei
  • baidu

网盘线路保留策略:

  • 只保留分享链接,不做驱动匹配
  • 分享链接直接写入 vod_play_url
  • vod_play_from 使用网盘名,如 quarkxunleibaidu

如果某种来源没有数据,则不保留空占位;最终只返回实际存在的线路。

播放设计

playerContent(flag, id, vipFlags) 按来源分流:

普通站内线路

  • 如果 id 不是绝对地址,则补全为站点完整 URL
  • 返回:
    • parse = 0
    • jx = 0
    • url = 完整播放链接
    • header = 基础请求头

网盘线路

flag 命中以下关键字时视为网盘线路:

  • baidu
  • quark
  • xunlei

对网盘线路不做二次解析,直接透传分享链接:

  • parse = 0
  • jx = 0
  • url = 原始分享链接
  • header = {}

这样可以保证上层仍能识别和消费网盘资源,不会因为 Spider 侧强行解析而丢失链接。

解析与兼容性策略

为了降低页面结构波动影响,实现上采用“选择器优先、正则兜底”的策略:

  • 列表与搜索主走 XPath
  • 详情页按钮参数用正则提取
  • 网盘链接通过 atob('...') 片段做 base64 解码

文本处理原则:

  • 缺失字段返回空字符串
  • 标题、备注、简介统一做空白折叠
  • 图片和详情链接统一补全为绝对地址

错误处理

实现遵循“失败可回退、最终返回空结果而非抛异常”的原则:

  • 页面请求失败时返回空结果
  • 单条线路解析失败时跳过该线路,继续解析其他线路
  • 网盘链接解码失败时跳过当前网盘项,不影响普通线路输出
  • 搜索页或详情页局部字段缺失时,保留其余可解析字段

测试设计

采用测试优先方式实现,先补单测,再写生产代码。

测试重点放在纯解析逻辑和结果结构,不依赖真实网络:

  1. 首页内容
    • 断言固定分类和筛选项按预期输出
  2. 分类列表
    • 断言 URL 构造与卡片解析正确
  3. 搜索
    • 断言 POST 请求参数正确
    • 断言搜索结果卡片可解析
  4. 详情
    • 断言能同时提取普通线路和网盘线路
    • 断言 vod_play_from / vod_play_url 正确分组
  5. 播放
    • 断言普通线路返回完整直链
    • 断言网盘线路直接透传分享链接

测试文件命名:

  • tests/test_低端影视.py

验收标准

满足以下条件即视为完成:

  • 新增 低端影视.py,可被仓库按现有方式加载
  • homeContent/categoryContent/detailContent/searchContent/playerContent 均返回符合当前项目习惯的数据结构
  • 详情页普通线路与网盘线路分开输出
  • 网盘分享链接在详情页和播放阶段都不会被丢弃
  • 新增单测通过,且不破坏现有测试