Files
tvboxzt/py/docs/superpowers/specs/2026-04-18-czzy-spider-design.md
T
2026-04-18 10:56:47 +08:00

7.2 KiB

厂长资源 Python 爬虫设计

目标

在当前仓库中新增一个符合 base.spider.Spider 接口的厂长资源爬虫,覆盖以下能力:

  • 分类列表
  • 详情页
  • 搜索
  • 播放解析

实现以网页抓取为主,不依赖私有 API,不改动 base/ 公共层。

范围

本次实现包含:

  • 新增独立站点脚本,暂定文件名为 厂长资源.py
  • 内置站点主机列表:
    • https://www.cz01.org
    • https://www.czzy89.com
  • 支持站内播放链接解析
  • 支持网盘资源保留并透传给上层

本次实现不包含:

  • 通用网页源框架抽象
  • 持久化 host 健康检查缓存
  • 对站点全部历史分类页面做完全覆盖

方案选择

采用 requests + lxml 直接抓取网页 DOM,并吸收参考插件 plugin_czzy 中已经验证过的页面结构与播放器解析规则。

不选择直接平移整份 JS 逻辑到 Python,原因是:

  • Python 代码可读性会更高
  • 更容易适配当前 Spider 接口
  • 只保留确实需要的站点规则,减少无关实现

模块边界

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

脚本内部职责拆分如下:

  • init
    • 初始化 host 列表、请求头、分类映射和运行期缓存
  • homeContent
    • 返回固定分类与筛选定义
  • categoryContent
    • 按分类拼接列表页 URL 并解析卡片
  • detailContent
    • 解析影片基础信息与播放列表
  • searchContent
    • 调用站内搜索页并复用卡片解析
  • playerContent
    • 解析剧集页和播放器 iframe,产出最终播放 URL
  • 若干私有辅助函数
    • host 回退
    • 页面请求
    • 卡片解析
    • 详情解析
    • 剧集解析
    • iframe 播放解析

Host 策略

站点域名容易变更,因此实现内置候选 host 列表。请求策略如下:

  1. 优先使用当前可用 host
  2. 若请求失败、返回空页面、或关键节点缺失,则依次尝试下一候选 host
  3. 一旦发现可用 host,将其提升为当前优先 host

判定页面是否可用时,不只看 HTTP 200,还要检查关键 DOM 是否存在,例如:

  • 分类页是否存在媒体卡片
  • 搜索页是否存在结果卡片或搜索结果容器
  • 详情页是否存在标题或播放列表容器

分类设计

分类使用稳定的字符串 ID,而不是数字 ID,避免额外映射层。首批支持以下分类:

  • movie
  • tv
  • anime
  • cn_movie
  • in_movie
  • ru_movie
  • ca_movie
  • jp_movie
  • kr_movie
  • western_movie
  • cn_drama
  • jp_drama
  • us_drama
  • kr_drama
  • intl_drama

每个分类映射到站点的固定路径,例如:

  • movie -> /movie_bt/movie_bt_series/dyy/page/{pg}
  • tv -> /movie_bt/movie_bt_series/dianshiju/page/{pg}

首页推荐 homeVideoContent 保持空列表,避免额外抓取首页并降低不稳定性。

列表与搜索解析

分类页与搜索页共用同一套卡片解析逻辑 parse_media_cards(html)

卡片提取策略:

  • 详情链接:优先取卡片内主链接 href
  • 标题:优先取图片 alt,其次链接 title,再回退到卡片文本
  • 图片:依次尝试 data-originaldata-srcsrc
  • 备注:优先取集数或清晰度角标,如 jidihdinfo

输出字段:

  • vod_id
    • 直接使用详情页相对路径或绝对路径,避免额外查表
  • vod_name
  • vod_pic
  • vod_remarks

分页策略:

  • page = 当前页
  • limit = 24 或按实际卡片数返回
  • pagecount = pg + 1 作为保守值
  • total 采用近似值,不依赖站点总数统计

如果当页没有结果,则返回空列表,并将 pagecount 设为当前页,避免上层无限翻页。

详情页设计

detailContent 通过 vod_id 请求详情页,提取:

  • vod_name
  • vod_pic
  • vod_year
  • vod_area
  • vod_actor
  • vod_director
  • vod_content

剧集来源分为两组:

  1. 站内播放
    • 来自 paly_list_btn
  2. 网盘资源
    • 来自 ypbt_down_list

播放源组织方式:

  • vod_play_from = "厂长资源$$$网盘资源"
  • vod_play_url = "<站内剧集串>$$$<网盘资源串>"

这样上层可以明确区分站内播放与网盘分享链接,不会混在同一条线路里。

剧集项格式:

  • 站内播放:标题$剧集页URL
  • 网盘资源:标题$分享链接

如果某一来源没有数据,则只返回存在的来源,不保留空占位。

播放解析设计

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

站内播放

  1. 请求剧集页
  2. 提取页面中的 iframe src
  3. 请求 iframe 页面,并带正确 Referer
  4. 按顺序尝试以下解析方式:
    • 解析 var playervar rand,做 AES 解密后读取 url
    • 读取并解混淆 data
    • 直接提取 mysvg
    • 直接提取 art.url
    • 解析包含 window.wp_nonce 的脚本作为兜底
  5. 成功后返回:
    • parse = 0
    • url = 最终播放 URL
    • playUrl = ""
    • header = {"User-Agent": "...", "Referer": "..."}

网盘资源

不做二次解析,直接返回原始分享链接,让上层播放器或网盘插件处理:

  • parse = 0
  • url = 原始分享链接
  • playUrl = ""

请求与兼容性

统一请求头:

  • 浏览器 User-Agent
  • 详情页与 iframe 页设置正确 Referer

必要时维护简单 cookie jar,用于:

  • 首次访问站点后记录下发 cookie
  • 后续请求带回同域 cookie

优先先做无状态请求;若验证发现某些页面必须依赖 cookie,再补上轻量 cookie 维护。

错误处理

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

  • 单个 host 请求失败时切换到备选 host
  • 单种播放器解析失败时继续尝试下一种规则
  • 所有规则失败时返回空 URL,而不是抛出异常中断调用
  • 详情页缺失部分字段时返回空字符串,不影响剧集列表输出

日志仅保留必要调试信息,避免刷屏。

测试设计

采用测试优先方式实现,先为关键解析逻辑补测试,再写生产代码。

测试重点放在纯解析函数,不依赖真实网络:

  1. 分类卡片解析
    • 输入参考 HTML 片段
    • 断言标题、封面、备注、详情链接解析正确
  2. 详情页剧集解析
    • 断言能区分站内播放与网盘资源
    • 断言重复链接会去重
  3. iframe 播放解析
    • 覆盖 iframe src 提取
    • 覆盖 mysvgart.urldata 等直接解析路径
  4. host 回退
    • 模拟首个 host 失败、第二个成功
    • 断言当前 host 被更新

集成验证以手工调用为辅:

  • homeContent
  • categoryContent
  • searchContent
  • detailContent
  • playerContent

如果当前仓库尚无正式测试框架,本次可以新增最小化 unittest 测试文件。

实施顺序

  1. 新增测试文件,覆盖纯解析与 host 回退
  2. 新增 厂长资源.py 基本骨架与分类映射
  3. 实现列表页和搜索页抓取
  4. 实现详情页和播放列表组织
  5. 实现播放器多策略解析
  6. 运行测试与基础手工验证

风险

  • 站点 HTML 结构可能随时变化
  • 播放器页混淆规则可能变更
  • 某些 host 可能对 Referer 或 cookie 敏感

对应策略:

  • 解析逻辑采用多重回退
  • host 失败时自动切换
  • 测试覆盖核心解析函数,降低回归风险