← 返回 Skill 列表
extension
分类: 数据与分析无需 API Key

番茄小说扫榜

番茄小说扫榜 · 开书决策助手 做网文选题最难的不是写作,是回答「现在该开什么书」。这个技能把番茄小说对外公开的榜单数据,翻译成一份能直接执行的选题方案。 它做什么 - 按你指定的频道与类目扫榜(男频 19 个类目、女频 18 个类目),阅读榜与新书榜双榜交叉取数,默认每榜前 50 名 - 采集官方榜单字段:排名与名次变化、在读量、总字数、连载状态、最近更新时间、官方题材标签 - 按 20 个维度拆解:在读结构与头部集中度、题材标签分布与稀缺组合、书名公式与高频词、简介钩子结构、蓝海红海判定矩阵 它交付什么(三件套) 1. 扫榜报告(.docx)——数据台账 + 5 条核心结论 + 题材与包装规律拆解 + 竞品对标表 + 蓝海红海矩阵 2. 开书建议(.docx)——5–10 个可开方案,每个附六维星级评分(赛道热度 / 供给缺口 / 差异化强度 / 留存潜力 / 执行难度 / 变现可行性),每维都给判据与数据、不做无理由打分;按综合星级排序,并分档为首选 / 次选 / 备选 / 探索 3. 扫榜长图(.png)——可直接转发到群或朋友圈的竖版长图 怎么用 直接说「扫榜,男频悬疑灵异,前 50 本」即可。技能会先与你确认频道、类目、榜单范围、样本量与输出目录,再开始取数分析,全程产物落盘可查。 数据说明 仅采集番茄小说对外公开的榜单数据与作品元信息(书名、作者、简介、官方题材标签),用于网文创作选题参考。 不抓取、不转载作品正文内容——作品正文接口需要登录,本技能不调用;可选的作品目录抽样也只读取章节标题与首发时间,用于计算更新节奏。 不涉及任何账号凭据。榜单仅收录 1000 在读以上作品,因此样本不含冷启动作品——报告中会明确标注统计截止日期与数据口径,官方数据与行业观察分开标注。

person作者: user_f9eb3d03hubcommunity

番茄小说榜单扫描与开书决策

针对用户在番茄小说指定的频道 + 类目做榜单扫描,把「现在什么火」翻译成「我该开什么书」。 交付三件套:扫榜报告(数据 + 分析)、开书建议(可执行选题)、扫榜长图(可分享 PNG)。

判定一切结论的唯一标准:是否有利于在番茄拿到留存与推荐量。番茄是免费阅读 + 广告变现 + 纯算法驱动平台,只按热度、供给、差异化排序,不按文学性或作者表达欲排序。

硬性交互契约

  1. 先确认参数,再动手。频道与类目由用户指定,不得自行假设。缺失时必须弹框询问(见步骤 0)。
  2. 数据来源双接口,缺一不可。番茄官网对榜单页的书名、简介做了PUA 码位编码(替换为 Unicode 私用区 PUA 字符),但作品详情接口返回的文本完全为明文(实测 300 本 PUA 残留 = 0)。因此必须同时走两个官方 JSON 接口:榜单接口拿排名 / 在读 / 状态 / 字数 / 更新时间,作品详情接口还原书名 / 作者 / 简介 / 官方标签,再按 bookId 对齐(见步骤 2)。不需要浏览器,也不需要截图 OCR。
  3. 一切数据标注口径。官方一手数据、行业观察、模型推断三类必须分开标注,不得混为一谈,不得把行业观察当官方数据陈述。
  4. 不代写可投稿正文。只产出数据、分析与选题层面的方案,正文由用户自行完成。
  5. 每一步的关键产出(rank-data.json 路径、接口原始响应、统计结果、长图 spec)都要落到磁盘并告知用户,不能只停留在对话里。

环境准备(首次使用或脚本报缺依赖时)

本 skill 的脚本走独立 Python 虚拟环境,不污染用户环境。下文 <skill> 指本 skill 的安装目录,<PY> 指虚拟环境解释器:

<PY> = C:/Users/Administrator/.workbuddy/binaries/python/envs/default/Scripts/python.exe

若该解释器不存在,或运行脚本时报 缺少 Pillow:

& "C:\Users\Administrator\.workbuddy\binaries\python\versions\3.13.12\python.exe" -m venv "C:\Users\Administrator\.workbuddy\binaries\python\envs\default"
& "<PY>" -m pip install --disable-pip-version-check Pillow

中文字体自动探测 C:\Windows\Fonts\msyh.ttc(微软雅黑),Windows 下默认可用。脚本报「未找到可用中文字体」时,检查该字体是否存在。

抓取环节零依赖:步骤 2 的双接口抓取只用 Python 标准库(urllib / json / concurrent.futures),无需安装任何包。只有渲染长图需要 Pillow。

产出 .docx 的依赖(步骤 6 走 tencent-docx 时):html-to-docx 转换引擎需要 python-docx / html-for-docx / beautifulsoup4 / lxml / httpx / click;把 Markdown 终稿转 HTML 还需要 markdown。这些一并装进同一个 venv:

& "<PY>" -m pip install --disable-pip-version-check "python-docx>=1.1,<2" "html-for-docx>=1.1,<2" "beautifulsoup4>=4.12,<5" "lxml>=5.2,<6" "httpx>=0.27,<1" "click>=8.1,<9" markdown

Windows 上 html-to-docx 的官方 setup-html-to-docx.sh 是 Bash 脚本、且默认走 ~/.venv-html-to-docx(Unix 路径布局),在纯 Windows 环境不可直接用。直接用上面的 venv + PYTHONPATH 指向 <plugin>/skills/html-to-docx/scripts 调用即可。

步骤 0 — 参数确认(不可跳过)

先弹框询问,一次问完;用户已在上文明确给出的项不再重复问。

| 参数 | 说明 | 默认 | |---|---|---| | 频道 | 男频 / 女频 | 必填,无默认 | | 类目 | 该类目下的具体分类,名称见 references/fanqie-rank-map.md 的类目表 | 必填,无默认 | | 榜单 | 阅读榜 / 新书榜 / 两个都要 | 两个都要 | | 样本量 | 每榜取前 N 名 | 50 | | 抽样读正文 | 是否抽样打开 8–12 本作品看目录与前几章 | 关闭(开启会显著变慢) | | 输出目录 | 产物落盘位置 | <workspace>/扫榜_<类目>_<YYYYMMDD>/ |

补充规则:

  • 类目如果用户说的名字在类目表里找不到(例如说「都市」但表里是「都市日常 / 都市脑洞 / 都市修真 / 都市高武 / 都市种田」),列出该频道下的相近类目让用户选,不要自己挑一个。
  • 用户只说「男频扫榜」没给类目时,列出该频道全部类目并说明「建议一次扫 2–3 个相邻类目做横向对比」,由用户决定。

步骤 1 — 定位榜单 URL

URL 规则:https://fanqienovel.com/rank/{频道码}_{榜单码}_{类目ID}

  • 频道码:1 = 男频,0 = 女频
  • 榜单码:2 = 阅读榜,1 = 新书榜
  • 类目 ID:见 references/fanqie-rank-map.md(含男频 19 个、女频 18 个类目的完整 ID 表)

例:https://fanqienovel.com/rank/1_2_504 = 男频阅读榜 · 抗战谍战。

类目 ID 会随平台调整变化,禁止长期硬编码。每次扫榜的第一步都是校验,有两条路(任选其一,推荐第二条):

  1. 抓一次榜单页 HTML,用正则 /rank/(\d+)_(\d+)_(\d+) 抽出当前导航里的真实链接与类目名,与参考表比对;
  2. 抓一次榜单页 HTML,解析 window.__INITIAL_STATE__.rank.rankCategoryTypeList——它是 {male:[{id,name},...], female:[...]} 结构,一次请求就能拿到该频道全部类目的权威 ID 与名称,不需要逐个类目去点。注意:这个字段只在页面内嵌状态里,不在 /api/rank/category/list 的响应里(该接口只返回 book_list / total_num / rankVersion / rankTypeText)。

不一致时以页面为准,并把新 ID 写回参考表。scripts/crawl_rank.py 已内置这一步(页面解析失败时回落内置类目表)。

榜单机制(引自官网榜单说明,扫榜时原样引用到报告里):

作品按照其在番茄小说中的分类进行划分排榜,排榜顺序按照在读数据排序,仅排 1000 在读以上的作品 阅读榜:30 万字以上、已签约未下架、已经开始推荐的番茄原创作品 新书榜:30 万字以下、已签约未下架、已经开始推荐的且未断更,完结未超过 90 天的番茄原创作品 排行榜每天下午 3 点前更新截止到上一日的排名数据

(以上为官网原文,原文无句末标点,引用时不要自行添加引号或改写词句。)

由此得到两条必须写进结论的推论:

  • 新书榜反映当下正在起量的题材(30 万字以下 = 近期开书),阅读榜反映已被验证的存量题材。判断「该开什么」必须两榜交叉看,只看一个榜会得出相反结论。
  • 榜单每天 15:00 前更新到前一日,必须在 15:00 之后抓取,并记录「统计截止日期」。15:00 前抓到的数据是两天前的。

步骤 2 — 抓取(双接口,必须都走)

番茄官网对榜单页 HTML 的书名、简介做了PUA 编码(私用区 PUA 字符),但作品详情接口返回的文本完全未编码。因此不要走「截图 + OCR」——直接调两个官方 JSON 接口,快、准、零识别误差(实测 300 本 PUA 残留 = 0)。

一条命令跑完抓取(推荐,脚本已把下面的细节全部实现,含分页、编码还原、并发、校验):

& "<PY>" "<skill>/scripts/crawl_rank.py" --channel 1 --category 1140,258,257 --lists 2,1 --top 50 --outdir "<输出目录>"

产出 <输出目录>/rank-data.json、raw_json/(接口原始响应)、crawl_log.txt(含校验结果)。下面的接口细节供排错与手工调用时参考。

接口 A|榜单列表(拿排名与在读数)

GET https://fanqienovel.com/api/rank/category/list
    ?app_id=1967&rank_list_type=3
    &offset={0,10,20,...}&limit=10
    &category_id={类目ID}&rank_version={上一页返回的 rankVersion 或空}
    &gender=1&rankMold={2=阅读榜, 1=新书榜}
  • gender:1 = 男频,0 = 女频。rankMold 与 URL 第二段一致(/rank/1_2_1140 → gender=1, rankMold=2)。
  • 必须在同一个榜单内先把第一页拿到的 rankVersion 回填给后续 offset 的请求,保证分页取自同一期快照。
  • 返回 {code:0, data:{book_list:[...], total_num, rankVersion, rankTypeText}}。total_num 通常为 100(榜单共 100 条)。
  • 每页固定 10 条,取前 N 名就请求 ceil(N/10) 次。
  • 早期用浏览器抓页面只能拿到 SSR 的前 10 条,且 readCount 是占位的 "0"——真实在读数在 read_count 字段(如 "664036" = 66.4 万),不要用错字段。

⚠ 最易踩的坑:rank_version 参数「可以为空,但不可以不存在」。 实测同一组参数连续 8 次:带 &rank_version=(值为空)稳定返回 n=10, total_num=100; 整个参数省略则返回 code=0, n=0, total_num=0——一个不报错的「假成功」, 极易被误判成「该类目没数据」或「接口已下线」。请求头(UA、Accept-Language)完全不影响结果。 排查榜单接口空列表时,第一件事就是确认 rank_version 在 URL 里(哪怕为空)。

book_list 每个条目的可靠字段:

| 字段 | 说明 | |---|---| | currentPos | 排名 | | rankPosDiff | 排名变化(0 = 无变化,正数 = 上升名次) | | read_count | 真实在读数(字符串,形如 "664036")——最重要的热度指标 | | creationStatus | "0" = 已完结,"1" = 连载中 | | wordNumber | 总字数(字符串)。阅读榜必然 ≥ 30 万,新书榜必然 < 30 万,可用来校验 rankMold 有没有接反 | | lastChapterTitle | 最新章节标题(未编码,可直接用) | | lastChapterUpdateTime | Unix 秒级时间戳,需自行转本地时间 | | bookId | 跨接口对齐与去重的主键 | | firstChapterItemId | 首章 itemId,可用于进一步抓目录 | | bookName / author / abstract | 已被PUA 编码,不可引用,一律用接口 B 覆盖 |

接口 B|作品详情(还原书名、作者、简介、官方标签)

GET https://fanqienovel.com/api/book/info?bookId={bookId}

注意参数名是驼峰 bookId,写成 book_id 会返回 {"code":-1,"message":"没有bookId"}。

返回 data 中的关键字段(全部为未编码文本):

| 字段 | 说明 | |---|---| | bookName / authorName | 干净书名与作者名 | | abstract | 干净简介 | | categoryV2 | 官方标签数组(JSON 字符串),每个元素含 Name / ObjectId / Dim / Gender / ExternalDesc。这是最可靠的标签来源,比作者自填的【】标签更能反映平台归类 | | wordNumber / creationStatus / status | 字数与状态 | | lastChapterTitle / lastPublishTime | 最新章节与发布时间 | | thumbUri | 封面图 |

性能与并发:单次请求约 0.4 秒。用 ThreadPoolExecutor(max_workers=6) 并发,300 本约 2 分钟。请求间隔留 1–2 秒重试退避即可,实测无频率限制。

落盘格式:写成 rank-data.json,schema 见 assets/rank-data.example.json。建议同时把接口原始响应按 raw_json/rank_...json 与 raw_json/book_{bookId}.json 落盘,便于复核与后续差分。抓完立即落盘,避免上下文丢失后重抓。

对齐规则:两个接口用 bookId 1:1 对齐(不是排名——排名会随榜单刷新变动)。接口 B 取不到的条目,在报告中标注该条书名来自接口 A 的编码文本并如实说明缺字。

校验清单(抓完必做):

  1. 每个榜单实际条数 = 目标样本量;
  2. 书名 / 作者 / 简介中 PUA 字符(U+E000–U+F8FF)总数为 0;
  3. 阅读榜所有作品 wordNumber ≥ 300000、新书榜所有作品 wordNumber < 300000(校验 rankMold 未接反);
  4. 同一榜单内书名去重后条数 = 样本量。

步骤 3 — 联网补全

用 WebFetch / WebSearch 检索以下信息,作为「行业观察」类证据,与官网数据分区标注:

  • 「番茄小说 <类目> <当前年月>」→ 近月题材动向、平台活动、征文赛道
  • 番茄官方公告(低质内容治理、发文规则、福利活动)→ 影响开书合规与收益预期
  • 该品类在女频/男频另一侧的对应题材热度 → 判断题材迁移机会

搜索结果一律标注「行业观察,自媒体口径,仅作趋势参考」。

步骤 4 — 统计与抽样

必做统计(用脚本,不要手算):

# 数据只含一个榜单
& "<PY>" "<skill>/scripts/rank_stats.py" --input rank-data.json --outdir .

# 数据含多个榜单(如 --lists 2,1 双榜):必须用 --list-index 指定,阅读榜与新书榜不可混合统计
& "<PY>" "<skill>/scripts/rank_stats.py" --input rank-data.json --outdir . --list-index 0 --prefix stats_read
& "<PY>" "<skill>/scripts/rank_stats.py" --input rank-data.json --outdir . --list-index 1 --prefix stats_new

不带 --list-index 而数据含多榜时,脚本会报错并列出各榜的 channel/category/list 与条数,让你按需指定—— 这是有意设计:把阅读榜(30 万字以上存量)与新书榜(30 万字以下增量)合并统计会得出错误的题材结论。 可用 --list-index 前先跑一次不带参数的,照它列出的清单选。

脚本兼容两种 rank-data.json 形状:扁平的 {meta, items} 与分榜的 {meta, lists:[{items}]}。

产出 stats.json + stats.md,覆盖:在读梯队分布、头部集中度(Top3/Top10 占比)、连载完结比例、更新时效、标签频次、书名长度与词频、数字/标点使用率。

脚本只做确定性统计,不做判断。判断由步骤 5 完成。

可选抽样(用户在步骤 0 开启时):从榜单中挑 8–12 本/类目(头部 3 本 + 中位 2 本 + 新书榜头部 3 本 + 新书榜末位 1 本),读取每本的完整目录并记录结构指标。

抽样方法:请求 https://fanqienovel.com/page/{bookId} 取 HTML(未编码),用正则抽出目录条目:

re.findall(r'\{"itemId":"(\d+)","needPay":\d+,"title":"(.*?)","isChapterLock":\w+,'
           r'"isPaidPublication":\w+,"isPaidStory":\w+,"volume_name":"(.*?)",'
           r'"realChapterOrder":"(\d+)","firstPassTime":"(\d+)"\}', html)

由此可稳定算出(全部是硬数据,不依赖读正文):

| 指标 | 算法 | |---|---| | 章节数 / 卷数 | 目录条目数 / volume_name 去重数(可看出该品类是否普遍不设卷) | | 平均章节字数 | wordNumber ÷ 章节数 | | 跨时天数 | (末章 firstPassTime − 首章 firstPassTime) ÷ 86400 | | 章/天、日更字数 | 章节数 ÷ 跨时天数、wordNumber ÷ 跨时天数 | | 首 5 章标题 | 用于判读开篇设定与金手指时机 |

重要限制:番茄的章节正文接口(/api/reader/*)要求登录,会返回「请先登录」。因此**「开篇第几段出冲突」「章末钩子形态」这类段级分析本次无法完成**,必须在报告中如实标注为未取数,并说明以目录结构 + 首章标题 + 简介替代、置信度为「中」。不要凭简介想象正文内容。

抽样结论必须标注样本量,不得当作全量事实。

步骤 5 — 分析(20 维,逐条过)

完整维度定义与判读标准见 references/scan-dimensions.md,按维度分段读取,不要整篇灌入。

五大组:结构热度(在读结构/换血率/活跃度)、题材差异化(标签分布/稀缺组合/跨界迁移)、包装层(书名公式/高频词/简介钩子/标签组合)、内容层(开篇设定/金手指形态/主角原型/章节节奏/篇幅体量)、判断层(蓝海红海矩阵/可开选题)。

分析必须遵守两条:

  • 每个结论后面挂数据。写「悬疑灵异类目被系统流占满」必须给出「Top 50 中 31 本带系统标签,占比 62%」。
  • 区分「已被验证」与「正在起量」。阅读榜高位 + 新书榜无同类 = 存量被验证但新供给少,是蓝海信号;两榜都挤满 = 红海,需要靠差异化变量切入。

步骤 6 — 产出三件套

三份产物的完整结构规范见 references/output-specs.md,严格按结构输出,不得省略标题。

① 扫榜报告(必做)→ 走 tencent-docx skill 生成 .docx 文件名:扫榜报告_<类目>_<YYYYMMDD>.docx 内容:数据面板 → 5 条核心结论 → Top N 原始数据表 → 热度结构分析 → 题材标签分布 → 书名与简介包装规律 → 内容层规律(若有抽样)→ 竞品对标表 → 蓝海红海矩阵 → 数据口径与免责声明。

② 开书建议(必做,单独成文)→ 走 tencent-docx skill 生成 .docx 文件名:开书建议_<类目>_<YYYYMMDD>.docx 内容:结论先行(主推方案 + 分档总览)→ 星级评分体系说明(六维锚点,先讲清尺子)→ 方案汇总对照表 → 5–10 个开书方案(按综合星级降序,每个含星级评分表 / 一句话卖点 / 书名 3 选 / 300 字内简介 / 主角与金手指含代价与失效条件 / 差异化变量 / 对标作品与雷同风险 / 目标读者与预期体量 / 风险与规避 / 为什么排在这个位次)→ 分档结论(首选 / 次选 / 备选 / 探索)→ 首发包装清单 → 更新与运营建议 → 与「番茄小说大纲审查」skill 的衔接建议。

星级规则:六维(赛道热度 / 供给缺口 / 差异化强度 / 留存潜力 / 执行难度 / 变现可行性)各 1–5 星,每维必须给判据并挂数据,禁止只打星不说理由;执行难度为反向计分(越好写星越高);综合星级取六维等权平均,保留到 0.5 星并附百分制。综合星级只用于排序,不替代风险判断。锚点定义见 references/output-specs.md。

数量规则:在 5–10 个之间自适应,不预设固定数量——由该类目实际存在几个有真实区分度的可开方向决定:方向多的类目写到 8–10 个,方向少的类目写 5 个即可。任何情况下不得少于 5 个、不得多于 10 个,不允许同一设定换皮(换书名、换金手指名词但核心变量相同)。若穷尽后确实凑不满 5 个有区分度的方案,如实说明该品类可开方向有限并给出实际数量,不要灌水凑数。

③ 扫榜长图(必做)→ 用脚本渲染 PNG

先按 assets/longimage-spec.example.json 的 schema 写出 longimage-spec.json,再渲染:

& "<PY>" "<skill>/scripts/render_longimage.py" --spec longimage-spec.json --out "扫榜长图_<类目>_<YYYYMMDD>.png"

可选参数:--width(逻辑宽度,默认 750,分享友好)、--scale(渲染倍率,默认 2)。

长图只放最硬的信息,控制在 8–12 屏:头部信息 → 4 个数字卡 → 子题材分布条形图 → TOP 10 榜单 → 书名高频词 → 开书方案 Top 3(带综合星级,并注明共几个方案)→ 数据来源与免责声明。

若 Pillow 不可用且无法安装,降级为「生成同名 HTML 长页 + 用 present_files 预览」,并在交付说明中明确告知未产出 PNG。

步骤 7 — 交付与衔接

用 present_files 一次性呈现三个文件(长图放第一位)。

交付后主动给出一句衔接建议:选定选题可交给 番茄小说大纲审查(男频修仙/玄幻/仙侠)或 番茄文娱小说大纲审查(文娱类)做全维度体检;不在覆盖范围内的类目,说明只能给通则建议。

数据口径与红线

  • 在读量级:番茄官方口径,单位为「万」,是榜单排序依据;榜单仅收录 1000 在读以上作品,因此榜单数据对冷启动作品完全不可见,分析尾部时必须在报告中说明这一点。
  • 口径分区:【官网数据】 / 【行业观察】 / 【模型推断】 三种前缀必须出现在报告对应段落。
  • 文本来源说明:书名、作者、简介与标签来自作品详情接口的原生文本,未经截图或 OCR,不存在识别误差;报告中要如实写「书名与标签通过作品详情接口还原,未经截图识别」,不要再沿用「经截图视觉识别补全,可能存在识别误差」的旧表述。
  • 涉及平台红线(涉政、涉黄、过度血腥、未成年人相关不当内容)的题材方向,直接指出并给替换方向,不帮忙包装。
  • 不承诺收益、不预测具体在读数字、不伪造「内部榜单」或非公开数据。

容错与降级

| 情况 | 处理 | |---|---| | 类目名对不上 | 列出该频道相近类目让用户选,不自行匹配 | | 榜单接口返回 book_list 为空(code=0 但 n=0) | 九成是 URL 里漏了 rank_version 参数——该参数必须存在(值可空),否则稳定返回空列表且不报错。其次检查 category_id / rankMold 是否与目标榜一致、rank_version 是否被上一组参数污染 | | 榜单接口返 404 / 空 body | 该类目 ID 可能已调整,回 references/fanqie-rank-map.md 用 rankCategoryTypeList 重新取 ID | | 榜单接口返回 {"code":-1,...} | 读 message 字段定位缺哪个参数(最常见的两个坑:作品详情接口的 bookId 写成了 book_id;榜单接口漏了 app_id) | | 作品详情接口取不到某本 | 记为缺失并如实报告,不用接口 A 的编码书名冒充;该条在报告中标注「书名来自榜单接口原始文本,存在缺字」 | | 阅读榜出现 <30 万字 / 新书榜出现 >30 万字的作品 | rankMold 接反了(2=阅读榜、1=新书榜),不是平台数据异常 | | 单个请求超时 / 连接重置 | 串行重试 3 次、退避 1.2s×n;并发抓 300 本时偶发失败属正常,失败清单单独重跑 | | 章节正文读不到 | 正常现象:/api/reader/* 系列接口要求登录(返回「请先登录」)。内容层分析改用「/page/{bookId} 页面里的完整目录」——章名与 firstPassTime 未编码,可算章节数、卷数、平均章节字数与日更字数 | | 类目名对不上 | 列出该频道相近类目让用户选,不自行匹配 | | 用户在 15:00 前要求扫榜 | 明确告知当期数据尚未更新,抓到的是前一日数据,并在报告中写明统计截止日期 | | 样本量不足(该类目上榜作品少于 N) | 如实记录实际样本量,不补位、不虚构 | | Pillow 不可用 | 按对应步骤的降级路径执行,并明确告知用户哪一环降级了。抓取环节不受影响(只用标准库) | | 用户要求扫「全站」而非指定类目 | 说明本 skill 以单类目深扫为单位;建议拆成 2–3 个类目分批扫,或先做男频/女频类目总览再选类目深扫 |

脚本自测(改动脚本或首次使用后建议跑一次)

用附带示例数据验证两个脚本能正常出产物,不消耗抓取成本:

& "<PY>" "<skill>/scripts/rank_stats.py" --input "<skill>/assets/rank-data.example.json" --outdir ./_selftest
& "<PY>" "<skill>/scripts/render_longimage.py" --spec "<skill>/assets/longimage-spec.example.json" --out ./_selftest/selftest.png

预期:_selftest/stats.json、_selftest/stats.md、_selftest/selftest.png(1500×4390 左右)三个文件生成成功。自测完删除 _selftest 目录。

长图支持的区块类型:stats(数字卡)、bars(条形分布)、toplist(榜单条目)、cards(卡片)、tags(标签云)、text(段落)、kv(键值行)、steps(编号步骤)。未知类型会直接报错并列出可选值。

资源索引

  • references/fanqie-rank-map.md —— 榜单体系、URL 规则、完整类目 ID 表、PUA 编码机制、双接口抓取 SOP 与可复用正则
  • references/scan-dimensions.md —— 20 个扫榜分析维度的定义、判读标准与结论写法
  • references/output-specs.md —— 三件套的固定结构与文案规范
  • scripts/crawl_rank.py —— 榜单双接口抓取(主路径):一条命令抓「频道 × 多类目 × 双榜 × 前 N 名」,自动还原文本并跑校验清单,产出 rank-data.json。只用标准库,无第三方依赖
  • scripts/rank_stats.py —— 榜单数据确定性统计(在读结构/标签频次/书名词频/更新时效),兼容扁平分榜两种 schema
  • scripts/render_longimage.py —— 长图渲染(JSON spec → PNG)
  • assets/rank-data.example.json —— 榜单数据结构 schema
  • assets/longimage-spec.example.json —— 长图数据结构 schema

降级备用(接口整体失效时才用)

  • scripts/fetch_rank.py —— 备用抓取路径:解析榜单页 window.__INITIAL_STATE__ + ?offset= 翻页
    • 区间校验重试 + PUA 字体解码。实测可稳定取到 Top 50(3/3 次成功),但比接口慢、需重试, 仅在 /api/rank/category/list 不可用时启用。
  • assets/pua-map.json —— 页面编码映射表(PUA 码位 → 汉字),已覆盖字体全部 362 个码位。 内容经 /api/book/info 明文交叉验证一致。
  • scripts/build_pua_map.py —— 字体 ID 变化时重建映射表:下载字体 → 解包 TTF → 渲染字形对照图, 再由模型读图填表。