L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

fanqie-rank

fanqie-rank

当用户需要获取番茄小说榜单数据(新书榜、阅读榜)时使用此技能 - 分析番茄小说各分类竞争程度、获取热门书籍信息(书名、作者、简介、在读数、字数)、了解当前市场趋势和热门题材

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: fanqie-rank description: "当用户需要获取番茄小说榜单数据(新书榜、阅读榜)时使用此技能 - 分析番茄小说各分类竞争程度、获取热门书籍信息(书名、作者、简介、在读数、字数)、了解当前市场趋势和热门题材" allowed-tools: Read, Bash

番茄榜单抓取 (fanqie-rank)

当用户需要获取番茄小说榜单数据(新书榜、阅读榜)时使用此技能。

触发词

番茄榜单、新书榜、阅读榜、榜单数据、抓取榜单、fanqie rank

使用场景

  • 分析番茄小说各分类竞争程度
  • 获取热门书籍信息(书名、作者、简介、在读数、字数)
  • 了解当前市场趋势和热门题材

榜单URL格式

https://fanqienovel.com/rank/{gender}_{type}_{category_id}

参数说明:

  • gender: 1=男频, 0=女频
  • type: 1=新书榜, 2=阅读榜
  • category_id: 分类ID

分类ID映射

男频分类 (19个)

ID分类名ID分类名
1141西方奇幻1140东方仙侠
8科幻末世261都市日常
124都市修真1014都市高武
273历史古代27战神赘婿
263都市种田258传统玄幻
272历史脑洞539悬疑脑洞
262都市脑洞257玄幻脑洞
751悬疑灵异504抗战谍战
746游戏体育718动漫衍生
1016男频衍生

女频分类 (18个)

ID分类名ID分类名
1139古风世情8科幻末世
746游戏体育1015女频衍生
248玄幻言情23种田
79年代267现言脑洞
246宫斗宅斗539悬疑脑洞
253古言脑洞24快穿
749青春甜宠745星光璀璨
747女频悬疑750职场婚恋
748豪门总裁1017民国言情

竞争程度分级

根据榜首在读数判断:

  • 🔴🔴 超红海: >50万在读
  • 🔴 红海: 30-50万在读
  • 🟡 中等偏高: 25-30万在读
  • 🟡 中等: 20-25万在读
  • 🟢 蓝海: <20万在读

技术要点

字体加密问题

番茄小说榜单页面使用字体加密,直接提取会得到乱码。

解决方案: 通过书籍详情页 /page/{bookId} 获取真实书名,该页面不使用字体加密。

数据提取

页面数据存储在 window.__INITIAL_STATE__ JSON中:

  • rank.book_list: 书籍列表
  • 每本书包含: bookId, bookName(加密), author(加密), abstract(加密), read_count, wordNumber

Python抓取代码

#!/usr/bin/env python3
import json
import re
import urllib.request
import time
from pathlib import Path

# 分类映射
MALE_CATEGORIES = {
    "1141": "西方奇幻", "1140": "东方仙侠", "8": "科幻末世",
    "261": "都市日常", "124": "都市修真", "1014": "都市高武",
    "273": "历史古代", "27": "战神赘婿", "263": "都市种田",
    "258": "传统玄幻", "272": "历史脑洞", "539": "悬疑脑洞",
    "262": "都市脑洞", "257": "玄幻脑洞", "751": "悬疑灵异",
    "504": "抗战谍战", "746": "游戏体育", "718": "动漫衍生",
    "1016": "男频衍生"
}

FEMALE_CATEGORIES = {
    "1139": "古风世情", "8": "科幻末世", "746": "游戏体育",
    "1015": "女频衍生", "248": "玄幻言情", "23": "种田",
    "79": "年代", "267": "现言脑洞", "246": "宫斗宅斗",
    "539": "悬疑脑洞", "253": "古言脑洞", "24": "快穿",
    "749": "青春甜宠", "745": "星光璀璨", "747": "女频悬疑",
    "750": "职场婚恋", "748": "豪门总裁", "1017": "民国言情"
}

def fetch_rank_page(gender, rank_type, category_id):
    """获取榜单页面HTML"""
    url = f"https://fanqienovel.com/rank/{gender}_{rank_type}_{category_id}"
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'}
    req = urllib.request.Request(url, headers=headers)
    with urllib.request.urlopen(req, timeout=30) as resp:
        return resp.read().decode('utf-8')

def parse_initial_state(html):
    """从HTML提取__INITIAL_STATE__数据"""
    match = re.search(r'window\.__INITIAL_STATE__\s*=\s*({.*?});', html, re.DOTALL)
    if match:
        return json.loads(match.group(1))
    return None

def get_real_book_info(book_id):
    """从书籍详情页获取真实信息(绕过字体加密)"""
    url = f"https://fanqienovel.com/page/{book_id}"
    headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)'}
    req = urllib.request.Request(url, headers=headers)
    try:
        with urllib.request.urlopen(req, timeout=10) as resp:
            content = resp.read().decode('utf-8')

        book_name = re.search(r'"bookName":"([^"]*)"', content)
        author = re.search(r'"author":"([^"]*)"', content)
        abstract = re.search(r'"abstract":"([^"]*)"', content)

        return {
            'bookName': book_name.group(1) if book_name else None,
            'author': author.group(1) if author else None,
            'abstract': abstract.group(1) if abstract else None
        }
    except Exception as e:
        print(f"获取书籍 {book_id} 失败: {e}")
        return None

def get_competition_level(top_read):
    """根据榜首在读数判断竞争程度"""
    read_wan = top_read / 10000
    if read_wan > 50:
        return "🔴🔴 超红海"
    elif read_wan > 30:
        return "🔴 红海"
    elif read_wan > 25:
        return "🟡 中等偏高"
    elif read_wan > 20:
        return "🟡 中等"
    else:
        return "🟢 蓝海"

def scrape_category(gender, rank_type, category_id, category_name):
    """抓取单个分类的榜单数据"""
    print(f"正在抓取: {category_name}")

    html = fetch_rank_page(gender, rank_type, category_id)
    data = parse_initial_state(html)

    if not data or 'rank' not in data:
        return None

    book_list = data['rank'].get('book_list', [])[:10]
    results = []

    for i, book in enumerate(book_list, 1):
        book_id = book.get('bookId', '')
        read_count = int(book.get('read_count', 0))
        word_count = int(book.get('wordNumber', 0))

        # 获取真实书籍信息
        real_info = get_real_book_info(book_id)
        time.sleep(0.3)  # 避免请求过快

        if real_info:
            results.append({
                'rank': i,
                'name': real_info['bookName'],
                'author': real_info['author'],
                'abstract': real_info['abstract'],
                'read': read_count / 10000,  # 转换为万
                'words': word_count / 10000
            })

    return results

def generate_markdown(all_data, title="番茄小说榜单数据"):
    """生成Markdown格式报告"""
    lines = [f"# {title}", "", f"> 数据采集时间:{time.strftime('%Y-%m-%d')}", ""]

    # 按竞争程度排序
    sorted_cats = sorted(all_data.items(),
                        key=lambda x: x[1]['top_read'], reverse=True)

    for cat_name, cat_data in sorted_cats:
        level = cat_data['level']
        top_read = cat_data['top_read']

        lines.append(f"## {cat_name}(榜首{top_read:.1f}万在读){level}")
        lines.append("")

        for book in cat_data['books']:
            lines.append(f"**【{book['rank']}】《{book['name']}》**")
            lines.append(f"- 作者:{book['author']}")
            lines.append(f"- 在读:{book['read']:.1f}万 | 字数:{book['words']:.1f}万")
            if book['abstract']:
                abstract = book['abstract'][:100] + "..." if len(book['abstract']) > 100 else book['abstract']
                lines.append(f"- 简介:{abstract}")
            lines.append("")

        lines.append("---")
        lines.append("")

    return "\n".join(lines)

# 主函数示例
def main():
    gender = 1  # 1=男频, 0=女频
    rank_type = 1  # 1=新书榜, 2=阅读榜
    categories = MALE_CATEGORIES if gender == 1 else FEMALE_CATEGORIES

    all_data = {}

    for cat_id, cat_name in categories.items():
        books = scrape_category(gender, rank_type, cat_id, cat_name)
        if books:
            top_read = books[0]['read'] if books else 0
            all_data[cat_name] = {
                'level': get_competition_level(top_read * 10000),
                'books': books,
                'top_read': top_read
            }
        time.sleep(1)  # 分类间隔

    # 生成报告
    md = generate_markdown(all_data, "番茄小说男频新书榜 TOP10")

    # 保存文件
    output_path = Path("fanqie-newbook-data.md")
    output_path.write_text(md, encoding='utf-8')
    print(f"数据已保存到: {output_path}")

if __name__ == "__main__":
    main()

使用方法

  1. 快速抓取: 运行上述Python脚本
  2. 自定义参数: 修改 gender 和 rank_type 变量
  3. 输出位置: 默认保存到当前目录的 fanqie-newbook-data.md

已有数据文件

最新抓取的完整数据保存在:

  • novel-writer-skills/templates/knowledge-base/genres/fanqie-male-newbook-top10.md
  • novel-writer-skills/templates/knowledge-base/genres/fanqie-trends-2025.md

注意事项

  1. 请求间隔建议 0.3-1 秒,避免被封IP
  2. 榜单数据每天下午3点更新
  3. 新书榜要求:30万字以下、已签约、未断更
  4. 阅读榜要求:30万字以上、已签约、已推荐
Skills enregistrées