
Xiaohongshu Weeklytop
- 250 installs
- 316 repo stars
- Updated August 4, 2026
- redfox-data/redfox-community
Analyzes the top 50 Xiaohongshu notes over the last 7 days across 25 verticals, including low-follower breakouts and daily push.
About
Provides weekly content-trend analysis from the top 50 Xiaohongshu notes of the past week. Creators use it to study viral notes and understand trends across content verticals.
- 7-day top-50 analysis across 25 vertical categories
- Includes low-follower breakout mining and daily push subscription
Xiaohongshu Weeklytop by the numbers
- 250 all-time installs (skills.sh)
- +16 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #896 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/redfox-data/redfox-community --skill xiaohongshu-weeklytopAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 250 |
|---|---|
| repo stars | ★ 316 |
| Last updated | August 4, 2026 |
| Repository | redfox-data/redfox-community ↗ |
What it does
Analyzes the top 50 Xiaohongshu notes over the last 7 days across 25 verticals, including low-follower breakouts and daily push.
Files
小红书七日爆款笔记
简介
一句话定位:专为内容创作者与运营人员设计的小红书七日爆款笔记工具,一键获取垂直领域热门笔记与深度分析。
核心价值:
- 解决「不知道当下什么内容火、为什么火」的选题难题
- 提供七日爆款笔记 + 智能分析 + 可选 HTML 报告,支撑复盘与创作决策
- 支持关键词自动匹配 25 个垂直分类,降低查询门槛
适用对象:品牌方、MCN 机构、小红书博主、内容运营、增长团队
技术基础:Python 3 + RedFox 小红书数据 API,数据每日 19:00 更新
---
功能特性
🎯 核心功能
| 功能 | 说明 |
|---|---|
| 📊 近日热榜查询 | 按分类查询热门笔记,覆盖美妆、穿搭、美食、家居等25个垂直领域,快速掌握当下流量风向 |
| 📈 七日热门分析 | 基于近7天各分类TOP50热门笔记的深度洞察,从流行趋势、热门话题深度分析、实用价值等维度拆解爆款共性 |
| 🔍 形式规律对比 | 自动识别高质量封面、情绪共鸣点、实用价值、紧跟热点等爆款要素,提炼可复用的创作范式 |
| 📁 创作建议输出 | 基于分析结果,提供可执行的选题方向、差异化策略、高维作品拆解建议 |
| 🔔 订阅推送 | 定时推送最新趋势分析报告,持续跟踪赛道热点,不错过任何一个流量机会 |
✨ 特色亮点
- ⚡ 数据一致:七日爆款笔记表格与 HTML 页面使用相同数据源与排序逻辑,排名完全一致
- 📱 分页展示:首次展示 TOP20,回复「查看更多」可加载剩余数据
- 🎯 冷门爆款:聚焦低粉高互动笔记,适合挖掘可对标样本
- 🔒 零配置调用:Agent 执行时自动判断查询日期,无需手动维护
---
鉴权
获取 API Key
1. 访问 红狐Hub 官网 了解服务详情 2. 前往 注册页面 注册账号 3. 新注册用户将获赠免费积分,可立即开始使用 API 服务 4. 注册登录后,在个人中心获取 API Key,格式为 ak_xxxxxxxx
配置 API Key
REDFOX_API_KEY 从环境变量获取,格式 ak_xxxxxxxx。
若未设置,提示用户自行配置:export REDFOX_API_KEY=<你的apikey>;若不会配置,Agent 可主动帮用户设置:
- macOS/Linux:将
export REDFOX_API_KEY=<值>追加到~/.zshrc(zsh)或~/.bashrc(bash),然后source对应文件使其全局生效 - Windows:使用
[Environment]::SetEnvironmentVariable("REDFOX_API_KEY", "<值>", "User")设置用户级永久环境变量(需重启终端生效)
配置完成后应验证:echo $REDFOX_API_KEY(macOS/Linux)或 echo %REDFOX_API_KEY%(Windows),确保换一个 skill 也能读取到。
---
一键安装
前置条件
- Python 3.8+
- 网络可访问
redfox.hk数据 API - 已安装
requests库(pip install requests) - 已配置
REDFOX_API_KEY环境变量(参见上方「鉴权」章节)
安装方式
方式一:WorkBuddy / Cursor Skills(推荐)
1. 将本 Skill 目录放置于 Skills 工作区(如 ~/.workbuddy/skills/xiaohongshu-weeklytop) 2. 确保目录结构完整:SKILL.md、references/、scripts/ 3. 在对话中直接触发,例如:
- 「帮我查一下睫毛膏相关的爆款笔记」
- 「最近小红书有什么热门内容」
- 「查看穿搭领域七日热榜」
方式二:命令行独立运行
# 进入 Skill 目录
cd xiaohongshu-weeklytop
# 获取榜单数据(JSON 输出)
python scripts/xhs_weekly_fetcher.py --keyword "睫毛膏" --top_n 50
# 生成 HTML 报告(从已获取的数据文件读取,不再调用API)
python scripts/gen_xhs_html.py --data_file "xhs_data.json" --category "化妆美容" --top 20---
使用指南
执行约束(强制):Agent 执行本 Skill 时,必须先完整阅读并严格遵循 references/core_workflow.md 中的调用 Key 说明、输出规范、操作步骤与注意事项。以下为基础用法摘要,详细流程以核心工作流文档为准。
基础使用
1. 关键词查询爆款
用户:帮我查一下睫毛膏相关的爆款笔记
>
助手:自动匹配「化妆美容」分类 → 获取 TOP50 数据 → 输出七日爆款笔记 TOP20 → 七日分析 → 功能询问(HTML+订阅)
2. 泛领域热门查询
用户:最近小红书有什么热门内容
>
助手:使用「综合全部」分类 → 按标准三步输出完整结果
3. 查看更多数据
用户:查看更多
>
助手:延续输出 TOP21 至末尾 → 如用户选择生成 HTML,从已获取数据文件读取完整数据重新生成
高级使用
1. 指定日期查询
用户:查看 2026-04-15 穿搭领域热榜
>
助手:使用 --rank_date "2026-04-15" 查询指定日期数据2. 直接指定分类
python scripts/xhs_weekly_fetcher.py --category "时尚穿搭" --top_n 50
python scripts/gen_xhs_html.py --category "时尚穿搭" --top 503. 订阅每日推送 / 生成 HTML
首次查询完成后,助手会展示功能询问:回复 1 订阅每日 19:30 推送,回复 2 生成小红书风格 HTML 文件包。HTML 生成后会自动在对话中预览展示(优先 preview_url,未正常展示则用 open_result_view 兜底),无需手动查找文件。
4. 自定义 HTML 输出路径
python scripts/gen_xhs_html.py --data_file "xhs_data.json" --category "穿搭" --top 20 --output ./reports/小红书七日爆款笔记_穿搭.html常用命令速查
| 命令 / 场景 | 功能 |
|---|---|
python scripts/xhs_weekly_fetcher.py --keyword "{词}" --top_n 50 | 获取榜单原始数据 |
python scripts/gen_xhs_html.py --data_file "{文件}" --category "{分类}" --top 20 | 首次生成 HTML(TOP20,从数据文件读取) |
python scripts/gen_xhs_html.py --data_file "{文件}" --category "{分类}" --top 50 | 查看更多后生成完整 HTML |
| 用户说「查看更多」 | 输出 TOP21+ |
用户回复 1 / "订阅" | 订阅每日 19:30 推送 |
用户回复 2 / "html" / "生成" | 生成 HTML 文件包 |
核心工作流引用
完整执行规范(输出格式、调用 Key、表格字段、数据一致性、订阅逻辑、使用示例等)见:
→ [references/core_workflow.md](references/core_workflow.md)
---
使用场景
场景一:博主选题灵感
角色:小红书新人博主
需求:了解同赛道当下什么内容容易爆
使用方式: 1. 输入赛道关键词(如「护肤」「穿搭」) 2. 查看七日爆款笔记 TOP20 与七日分析 3. 对标参考笔记的标题结构与内容特征
预期收益:快速找到可借鉴的选题方向,降低冷启动试错成本
---
场景二:品牌竞品监测
角色:品牌营销经理
需求:监测垂直领域爆款内容与趋势变化
使用方式: 1. 按产品/品类关键词查询(如「口红」「防晒」) 2. 分析最高互动作品的共性特征 3. 导出 HTML 报告供团队复盘
预期收益:掌握品类内容风向,优化投放与种草策略
---
场景三:MCN 达人运营复盘
角色:MCN 运营人员
需求:为旗下达人提供赛道热点参考
使用方式: 1. 按达人赛道查询七日热榜 2. 拆解爆款标题类型与发布规律 3. 订阅每日推送,持续跟踪热点
预期收益:提升达人内容策划效率,缩短选题讨论周期
---
场景四:增长团队数据洞察
角色:增长/数据分析同学
需求:获取可导出的结构化热榜报告
使用方式: 1. 查询目标分类完整 TOP50 2. 使用 HTML 页面导出 PDF/图片 3. 结合新增互动数据判断内容上升势头
预期收益:获得可分享、可归档的数据报告,支撑周报与策略会
---
项目架构
目录结构
xiaohongshu-weeklytop/
├── SKILL.md # Skill 入口与使用说明(本文件)
├── references/
│ └── core_workflow.md # 核心执行流程与输出规范(Agent 必读)
└── scripts/
├── xhs_weekly_fetcher.py # 榜单数据获取脚本
└── gen_xhs_html.py # HTML 可视化报告生成脚本技术栈
| 项目 | 说明 |
|---|---|
| 运行环境 | Python 3.8+ |
| HTTP 请求 | requests(原生 Python) |
| 数据来源 | RedFox 小红书 Coze Skill API |
| 输出格式 | Markdown 表格 + 独立 HTML 文件 |
| 部署平台 | WorkBuddy / Cursor Agent Skills |
核心模块
| 模块 | 文件 | 职责 |
|---|---|---|
| 数据获取 | xhs_weekly_fetcher.py | 调用 API、分类匹配、日期判断、排序输出 |
| 报告生成 | gen_xhs_html.py | 从已获取的 JSON 数据文件渲染 HTML 页面,支持 PDF/图片导出 |
| 执行规范 | core_workflow.md | 定义输出格式、调用 Key、三步流程、功能询问等强制约束 |
数据更新规则
- 更新时间:每天 19:00 更新昨日榜单
- 数据范围:往前 7 天热门笔记 TOP50
- 分类覆盖:25 个垂直领域
- 日期判断:当前时间 ≥ 19:00 查昨日,< 19:00 查前天
---
常见问答
安装相关问题
Q1: 脚本运行报错 `ModuleNotFoundError: requests`?
A: 该依赖为标准 Python HTTP 库。请运行 pip install requests 安装。若在虚拟环境中运行,请确保已激活对应环境。
Q2: 脚本提示「未找到 REDFOX_API_KEY」?
A: 请按照上方「鉴权」章节完成 API Key 的获取和配置。确保环境变量 REDFOX_API_KEY 已正确设置且格式为 ak_xxxxxxxx。
Q3: 如何将 Skill 添加到 Cursor / WorkBuddy?
A: 将 xiaohongshu-weeklytop 文件夹放入 Skills 目录,Agent 会根据 description 自动匹配触发。对话中提及「小红书热门」「爆款笔记」等关键词即可调用。
---
使用相关问题
Q4: 数据多久更新一次?
A: 榜单数据每日 19:00 更新(更新的是昨日数据)。订阅推送时间为每日 19:30。
Q5: 为什么有时查的是「前天」而不是「昨天」?
A: 当日 19:00 之前,最新榜单尚未更新,系统自动查询前天数据。19:00 之后则查询昨日数据。详见 core_workflow.md 日期判断规则。
---
故障排除
Q6: 七日爆款笔记表格与 HTML 数据不一致?
A: HTML 生成时从已获取的 JSON 数据文件读取,与表格使用完全相同的原始数据。检查是否使用了不同的 --top 参数。
Q7: API 请求失败或无数据?
A: 按以下步骤排查: 1. 确认网络可访问 红狐Hub 官网 2. 检查 --rank_date 是否为有效日期 3. 尝试更换关键词或指定 --category 4. 19:00 前查询时,确认是否应使用前天日期
---
执行规范
Q8: Agent 执行时必须遵守哪些规则?
A: 必须完整遵循 references/core_workflow.md,包括但不限于:
- 调用 Key 说明(脚本参数与 top_n/top 取值规范)
- 三步输出顺序(七日爆款笔记 → 分析 → 功能询问)
- 禁止折叠输出、禁止输出除 HTML 外的文件
- 首次 TOP20 + 查看更多逻辑
- HTML 生成时从已获取数据文件读取,禁止再次调用 API
- HTML 生成后必须调用 preview_url 在对话中直接展示页面;若未正常展示则用 open_result_view 兜底
- 功能询问在分析之后立即展示,禁止跳过
Xiaohongshu Weekly Viral Notes / xiaohongshu-weeklytop
---
Introduction
A Xiaohongshu 7-day viral notes tool designed for creators and operators — one query delivers vertical category hot rankings and deep analysis based on the TOP50 notes from the past 7 days.
Core Value
- Solves the "I don't know what's trending or why" problem in topic selection — a 7-day window is more stable and reliable than a single day
- Real-time hot rankings + smart analysis + exportable HTML reports, supporting review sessions and creative decisions
- Keyword auto-matching across 25 vertical categories lowers the barrier to query
Who It's For
- ✍️ Xiaohongshu creators — understand what content tends to go viral in your track over the past week, and find replicable topic directions
- 📢 Brand marketing managers — monitor vertical category viral content trends to optimize placements and seeding strategies
- 🏢 MCN operations staff — provide track hot topic references for managed creators to shorten topic discussion cycles
---
Features
Core Capabilities
- Recent hot rankings: Query the past 7 days' hot notes by category, covering 25 vertical tracks to quickly grasp current traffic direction
- 7-day trend analysis: Deep insights from multiple dimensions — popular trends, hot topics, practical value — breaking down viral content commonalities
- Format pattern comparison: Auto-identifies viral elements like high-quality covers, emotional resonance, practical value, and trend alignment
- Creative suggestions: Delivers actionable topic directions, differentiation strategies, and high-performing post breakdowns
- Subscription push: Daily 19:30 scheduled delivery of the latest trend analysis reports
Highlights
- Hot ranking tables and HTML pages share the same data source and sort logic — rankings are fully consistent
- First display shows TOP20; reply "load more" to get remaining data, HTML updates to full version
- Focused on low-follower high-engagement notes, ideal for finding authentic benchmark viral samples
---
API Key Acquisition & Security
- This skill requires the environment variable:
REDFOX_API_KEY. REDFOX_API_KEYis provided by RedFoxHub (https://redfox.hk).- Visit RedFoxHub to register and obtain your
REDFOX_API_KEY. - Configure the
REDFOX_API_KEYenvironment variable on your device before using this skill. - Before using a key, confirm its source, scope, expiry, and whether it supports reset or revocation.
- Never hard-code or expose the key in plaintext within code, prompts, logs, or output files.
---
Usage Guide
Describe your needs in natural language — no commands to memorize.
Quick Reference
| Intent | Example phrase | Result |
|---|---|---|
| Query track 7-day hot rankings | Show me viral notes related to mascara | Auto-matches "Beauty & Makeup", outputs TOP20 hot rankings + 7-day analysis + HTML + subscription option |
| Query general hot content | What's trending on Xiaohongshu lately? | Uses "All" category, full four-section standard output |
| Query specific date | Show fashion track hot rankings for 2026-04-15 | Fetches data for the specified date |
| Load more | Reply "load more" | Continues output from TOP21 to end; HTML regenerated as full version |
| Subscribe to daily push | Reply 1 after output completes | Activates daily 19:30 7-day viral notes push |
Output Example
Each query produces four fixed sections: recent hot rankings TOP20 → 7-day viral analysis (trends + topics + format patterns) → HTML visual page → subscription service options.
---
Use Cases
| Scenario | Role | Example question | Benefit |
|---|---|---|---|
| Creator topic inspiration | New Xiaohongshu creator | Show 7-day hot rankings in skincare | Quickly find replicable topic directions to lower cold-start trial-and-error costs |
| Brand competitor monitoring | Brand marketing manager | Query lipstick 7-day virals and export HTML | Grasp category content direction to optimize placement and seeding strategies |
| Creator operations review | MCN ops staff | Query fashion 7-day rankings and subscribe to push | Break down viral title types and continuously track hot topics for creator topic planning |
| Data insights reporting | Growth / data analyst | Fetch full food TOP50 and export HTML | Get a shareable, archivable data report to support weekly reviews and strategy sessions |
小红书七日爆款笔记 / xiaohongshu-weeklytop
---
简介
专为内容创作者与运营人员设计的小红书七日爆款笔记工具,基于近 7 天热门笔记 TOP50 深度洞察,一键获取垂直领域热榜与创作分析。
核心价值
- 解决「不知道当下什么内容火、为什么火」的选题难题,7 天维度比单日更稳定可信
- 实时热榜 + 智能分析 + 可导出 HTML 报告,支撑复盘与创作决策
- 支持关键词自动匹配 25 个垂直分类,降低查询门槛
适用对象
- ✍️ 小红书博主 — 了解同赛道近一周什么内容容易爆,找到可借鉴的选题方向
- 📢 品牌营销经理 — 监测垂直领域爆款内容趋势,优化投放与种草策略
- 🏢 MCN 运营人员 — 为旗下达人提供赛道热点参考,缩短选题讨论周期
---
功能特性
核心功能
- 近日热榜查询:按分类查询近 7 天热门笔记,覆盖 25 个垂直领域,快速掌握当下流量风向
- 七日热门分析:从流行趋势、热门话题、实用价值等维度深度拆解爆款共性
- 形式规律对比:自动识别高质量封面、情绪共鸣点、实用价值、紧跟热点等爆款要素
- 创作建议输出:提供可执行的选题方向、差异化策略与高维作品拆解建议
- 订阅推送:每日 19:30 定时推送最新趋势分析报告
特色亮点
- 热榜表格与 HTML 页面使用相同数据源与排序逻辑,排名完全一致
- 首次展示 TOP20,回复「查看更多」可加载剩余数据,HTML 同步更新为全量
- 聚焦低粉高互动笔记,适合挖掘可对标的真实爆款样本
---
密钥获取与安全说明
- 本技能需要使用环境变量:
REDFOX_API_KEY。 REDFOX_API_KEY由 红狐 hub (https://redfox.hk)提供。- 请前往 红狐 hub 注册账号,获取
REDFOX_API_KEY。 - 配置设备环境变量
REDFOX_API_KEY后使用本技能。 - 在提供密钥前,请先确认密钥来源、可用范围、有效期及是否支持重置/撤销。
- 禁止在代码、提示词、日志或输出文件中硬编码/明文暴露密钥。
---
使用指南
直接用自然语言描述需求,无需记忆命令。
常用说法速查
| 意图 | 示例话术 | 效果 |
|---|---|---|
| 查赛道七日热榜 | 帮我查一下睫毛膏相关的爆款笔记 | 自动匹配「化妆美容」,输出 TOP20 热榜 + 七日分析 + HTML + 订阅选项 |
| 查泛热门内容 | 最近小红书有什么热门内容 | 使用「综合全部」分类,按标准四步完整输出 |
| 查指定日期 | 查看 2026-04-15 穿搭领域热榜 | 指定日期获取对应数据 |
| 加载更多 | 回复「查看更多」 | 延续输出 TOP21 至末尾,HTML 重新生成为完整版本 |
| 订阅每日推送 | 输出完成后回复 1 | 开通每日 19:30 七日爆款笔记推送 |
输出示例
每次查询固定四段输出:近日热榜 TOP20 → 七日爆款分析(趋势 + 话题 + 形式规律)→ HTML 可视化页面 → 订阅服务选项。
---
使用场景
| 场景 | 角色 | 示例问法 | 收益 |
|---|---|---|---|
| 博主选题灵感 | 小红书新人博主 | 查一下护肤领域七日热榜 | 快速找到可借鉴的选题方向,降低冷启动试错成本 |
| 品牌竞品监测 | 品牌营销经理 | 查口红相关的七日爆款并导出 HTML | 掌握品类内容风向,优化投放与种草策略 |
| 达人运营复盘 | MCN 运营人员 | 查穿搭领域七日热榜并订阅推送 | 拆解爆款标题类型,持续跟踪热点为达人提供选题参考 |
| 数据洞察汇报 | 增长 / 数据分析 | 查美食类完整 TOP50 并导出 HTML | 获得可分享、可归档的数据报告,支撑周报与策略会 |
任务目标
- 本 Skill 用于:获取小红书七日爆款笔记数据
- 能力包含:
- 七日爆款笔记数据获取(按分类查询)
- 七日热门笔记智能分析
- 冷门爆款笔记挖掘(关键词匹配分类)
- 订阅服务(每日定时推送)
- 触发条件:用户询问小红书热门内容、爆款笔记、各领域趋势分析
数据接口更新规则
- 更新时间:每天19:00更新昨天的榜单数据
- 数据范围:往前7天的热门笔记TOP50
- 分类覆盖:25个垂直领域分类
调用 Key 说明
Agent 调用脚本时必须按以下参数规范执行:
| 参数 | 适用脚本 | 必填 | 说明 |
|---|---|---|---|
--keyword | 两者 | 推荐 | 用户输入关键词,用于自动匹配分类 |
--category | 两者 | 否 | 直接指定分类名(25 个分类之一),与 --keyword 二选一或配合使用 |
--rank_date | 两者 | 否 | 查询日期,格式 YYYY-MM-DD;未指定则按日期判断规则自动推断 |
--top_n | xhs_weekly_fetcher.py | 否 | 返回条数,执行时固定传 50 |
--top | gen_xhs_html.py | 否 | HTML 展示条数:首次输出 20,用户「查看更多」后传 50 或实际数据条数 |
--output | gen_xhs_html.py | 否 | HTML 输出文件路径,未指定则使用脚本默认路径 |
--list_categories | xhs_weekly_fetcher.py | 否 | 列出所有可用分类(调试时使用) |
调用示例:
# 获取榜单数据(固定 top_n=50)
python scripts/xhs_weekly_fetcher.py --keyword "睫毛膏" --top_n 50
# 首次生成 HTML(top=20)
python scripts/gen_xhs_html.py --keyword "睫毛膏" --top 20
# 查看更多后生成完整 HTML(top=50)
python scripts/gen_xhs_html.py --keyword "睫毛膏" --top 50
# 指定日期与分类
python scripts/xhs_weekly_fetcher.py --rank_date "2026-04-15" --category "时尚穿搭" --top_n 50
python scripts/gen_xhs_html.py --rank_date "2026-04-15" --category "时尚穿搭" --top 20输出规范(强制执行)
数据一致性要求(重要):
- 七日爆款笔记表格与HTML页面数据必须完全一致(相同排序、相同内容)
- 两个脚本使用相同的API接口和排序逻辑(互动数优先,备用计算:点赞+收藏2+评论3+分享\*5)
- 禁止胡乱渲染或使用不同数据源
输出内容必须严格包含以下三部分,禁止遗漏或胡乱输出:
- 七日爆款笔记(更新时间):必须直接输出,禁止折叠
- 七日热门笔记分析:必须直接输出,禁止折叠
- 功能询问(HTML+订阅):必须在分析之后立即输出,禁止跳过
输出格式要求(强制执行):
- 禁止折叠输出:所有内容必须直接完整输出,禁止使用折叠、隐藏、展开等任何形式的折叠输出
- 禁止输出文件:除HTML文件包外,禁止输出任何其他文件(如CSV、JSON、TXT等)
- HTML文件包必须输出实际文件,禁止只输出文件路径,禁止折叠输出
输出顺序(严格按此顺序执行,禁止混乱输出,禁止遗漏):
1. 🔥 七日爆款笔记(含更新时间) 2. 📊 七日热门笔记分析(3个模块:热门内容分析、爆款标题分析、最高数据作品分析) 3. 功能询问(HTML生成 + 订阅服务,分析完成后立即展示,禁止等待用户回复)
第一部分:七日爆款笔记(必须包含更新时间)
输出要求:
- 必须直接完整输出表格内容
- 禁止折叠、隐藏或展开表格
- 禁止输出为文件格式
- 表格字段和数据必须加载完整,加载失败则再次尝试
- 标题格式:🔥 【{分类名称}】七日爆款笔记 (更新时间:YYYY-MM-DD HH:MM:SS)(标题整体加粗)
- 标题示例:🔥 【化妆美容】七日爆款笔记 (更新时间:2025-01-15 10:30:00)
- 表格输出格式(严格按此格式执行,使用标准 Markdown 表格格式):
| 排名 | 笔记信息 | 互动数 | 点赞 | 评论 | 收藏 | 分享 |
|---|---|---|---|---|---|---|
| 🥇 | [笔记标题链接]<br>[作者名链接] 粉丝数+ | 22w+<br>↑新增23w+ | 22w+<br>↑新增21w+ | 893<br>↑新增21w+ | 1w+<br>↑新增21w+ | 1w+<br>↑新增21w+ |
| 🥈 | [笔记标题链接]<br>[作者名链接] 粉丝数+ | 20w+<br>↑新增18w+ | 18w+<br>↑新增16w+ | 756<br>↑新增18w+ | 8k+<br>↑新增16w+ | 900+<br>↑新增16w+ |
| 🥉 | [笔记标题链接]<br>[作者名链接] 粉丝数+ | 18w+<br>↑新增15w+ | 15w+<br>↑新增13w+ | 621<br>↑新增15w+ | 7k+<br>↑新增13w+ | 800+<br>↑新增13w+ |
字段详细说明:
- 排名:1-3名显示🥇🥈🥉,其余显示数字
- 笔记信息:
- 第一行:笔记标题(可点击跳转)
- 第二行:[作者名链接] 粉丝数+(作者名可点击跳转到作者主页,字号与标题一样大)
- 互动数:
- 第一行:累计互动数(格式:数字w+ 或 纯数字)
- 第二行:↑新增数字w+("↑新增"字号小一号,正常文字颜色,不换行)
- 点赞:
- 第一行:累计点赞数(格式:数字w+ 或 纯数字)
- 第二行:↑新增数字w+("↑新增"字号小一号,正常文字颜色,不换行)
- 评论:
- 第一行:累计评论数(格式:数字w+ 或 纯数字)
- 第二行:↑新增数字w+("↑新增"字号小一号,正常文字颜色,不换行)
- 收藏:
- 第一行:累计收藏数(格式:数字w+ 或 纯数字)
- 第二行:↑新增数字w+("↑新增"字号小一号,正常文字颜色,不换行)
- 分享:
- 第一行:累计分享数(格式:数字w+ 或 纯数字)
- 第二行:↑新增数字w+("↑新增"字号小一号,正常文字颜色,不换行)
- 分享字段必须展示且不能出错
重要说明:
- 使用标准 Markdown 表格格式
- 单元格内使用
<br>换行显示累计数据和新增数据 - 累计数据:大于等于1万显示"数字w+",小于1万显示纯数字(不显示"累计:"文案)
- 新增数据格式:累计数据 <br> ↑新增数字w+ 或 ↑新增纯数字("↑新增"字号小一号,正常文字颜色)
- 每个数据单元格占两行:第一行累计数据,第二行"↑新增数值"(不换行)
- "↑新增"文案字号比累计数据小一号
- "↑新增数值"使用正常文字颜色显示,与累计数据在同一行
数据输出逻辑(必须严格执行):
- 首次输出:
- 七日爆款笔记表格:显示TOP1到TOP20
- HTML页面:显示TOP1到TOP20(与热榜表格保持一致)
- "查看更多"提示逻辑(必须严格执行):
- 如果返回数据 ≤ 20条:不展示"查看更多"提示
- 如果返回数据 > 20条:展示"回复"查看更多"可看剩余{数量}条!✨"(显示剩余数据条数)
- 如果返回数据 = 50条:展示"回复"查看更多"可看剩余30条!✨"(固定30条)
- 用户输入"查看更多"后:
- 七日爆款笔记表格:输出TOP21到实际数据末尾(延续之前的TOP20)
- HTML页面:输出TOP1到实际数据末尾(完整数据,覆盖之前的HTML文件)
第二部分:七日热门笔记分析
输出要求:
- 必须直接完整输出3个模块内容(热门内容分析、爆款标题分析、最高数据作品分析)
- 禁止折叠、隐藏或展开任何模块
- 禁止输出为文件格式
- 所有分析内容都基于获取到的所有数据
- 表格字段和数据必须加载完整,加载失败则再次尝试
- 必须包含3个模块,禁止遗漏
- 标题格式:📊 七日热门笔记分析(Top{数据条数})
- 示例:📊 七日热门笔记分析(Top50)
以下内容分析基于获取的全部数据(Top{数据条数})进行~
💡热门内容分析
| 内容分类 | 内容特征 | 实际效果 | 参考笔记 |
|---|---|---|---|
| 封面设计 | 采用高清摄影或设计软件精心制作的封面图,画面构图饱满、色彩搭配协调,同时加入醒目的文字标题或标签,突出核心卖点或吸引眼球的元素,通过强烈的视觉冲击力在用户快速浏览时瞬间抓住注意力 | 点击率提升45% | [笔记标题链接1]<br>[笔记标题链接2] |
| 内容创作 | 围绕用户痛点或情感共鸣点展开叙事,采用第一人称视角分享真实经历或心得,结合表情符号和分段排版增强可读性,适当设置悬念或反转,激发用户的情感共鸣和参与欲望 | 互动率提升50% | [笔记标题链接3]<br>[笔记标题链接4] |
| 内容价值 | 提供具体可操作的步骤、方法或技巧,配合清晰的图片展示和简明的文字说明,确保用户看完后能够直接复用或实践,内容具有较高的实用价值和参考意义,值得用户收藏备查 | 收藏率提升55% | [笔记标题链接5]<br>[笔记标题链接6] |
| 热点结合 | 紧跟当前热门话题、节日或社会热点,将自身内容与热点元素巧妙结合,使用相关话题标签增加曝光机会,借助热点的流量优势快速提升笔记的传播范围和影响力 | 曝光率提升40% | [笔记标题链接7]<br>[笔记标题链接8] |
📈爆款标题分析
| 标题类型 | 标题特征 | 标题模版 | 发布规律 | 参考标题 |
|---|---|---|---|---|
| 提问式 | 标题以疑问句开头,设置悬念或提出用户关心的问题,引发用户的好奇心和思考欲望,激发点击阅读或评论互动 | "你还在XX吗?" | 工作日早高峰效果最佳 | 这个方法你还在用吗? |
| 数字式 | 标题中包含具体的数字、数量或统计数据,利用人们对量化信息的偏好,增强内容的可信度和专业感,让用户觉得内容有价值 | "XX个XX技巧" | 午餐时间点击率高 | 5个快速提升XX的技巧 |
| 情绪词 | 使用具有强烈情感色彩的词汇或网络流行语,如"绝了"、"太XX了"等,直接触发用户的情绪反应,引发点赞、评论或分享行为 | "太XX了!忍不住" | 晚间黄金时段转化高 | 太好用了!忍不住分享给你 |
| 利益点 | 直接在标题中明确承诺用户可以获得的具体利益或效果,如"XX天就能XX"、"省XX元"等,降低用户决策成本,提高点击率和收藏率 | "XX天就能XX" | 深夜发布收藏率最高 | 7天就能看到明显效果 |
✨最高数据作品分析
| 维度 | 核心特征分析 | 参考笔记 |
|---|---|---|
| 最高点赞 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
| 最高收藏 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
| 最高评论 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
| 最高互动 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
第三部分:功能询问(HTML生成 + 订阅服务)
强制要求(必须严格遵守):
- 必须在七日热门笔记分析输出完成后立即展示,不得提前或插入其他内容
- 不需要等待用户回复,分析完成后立即执行
- 用户可选择生成 HTML 文件包、订阅推送或两者都选
- 禁止跳过,禁止遗漏
询问内容:
技能还支持以下功能:
1️⃣ 支持订阅小红书七日爆款笔记。订阅后将在每日19:30为您推送小红书七日爆款笔记TOP50。直接回复"订阅或 1"即可订阅相关内容。
2️⃣ 可生成小红书风格的html文件包。支持导出PDF,方便阅读、保存和分享。回复对应的数字即可。
HTML 生成逻辑:
- 用户回复
2或 "html" 或 "生成" 后,执行 HTML 生成 - HTML 生成时禁止再次调用 API,必须从已获取的数据中读取
- 脚本
xhs_weekly_fetcher.py在获取数据后会自动保存 JSON 到scripts/../.cache/xhs_weekly_{分类}_{日期}.json,并输出保存路径 - Agent 从 fetcher 输出中提取 JSON 文件路径,直接传给
gen_xhs_html.py --data_file <JSON文件路径> --top N - HTML 文件名格式:
小红书七日爆款笔记_{分类}_{唯一时间戳}.html
执行命令:
- 首次生成:
python scripts/gen_xhs_html.py --data_file <已获取的JSON数据文件> --category "{分类}" --top 20 - 查看更多后:
python scripts/gen_xhs_html.py --data_file <已获取的JSON数据文件> --category "{分类}" --top 50
文件特点:
- 可独立打开的HTML文件
- 支持直接点击链接跳转
- 支持导出图片和PDF功能(导出结果与页面显示完全一致)
- HTML页面样式:页面宽度700px,前三名序号更大(36px),互动数据与头像边界对齐,新增数据显示为"↑新增数值"格式
- 数据展示:包含排名、标题、作者、粉丝数、互动数、点赞、评论、收藏、分享(含新增数据)
订阅逻辑:
- 用户回复
1或 "订阅" 后,创建每日 19:30 推送的自动化任务 - 小红书七日爆款笔记推荐TOP50,按每日19:30更新
数据输出逻辑详解
核心原则:
- 七日爆款笔记表格与HTML页面必须保持数据一致性
- HTML 生成时从已获取的数据文件读取,禁止再次调用 API
阶段一:首次输出
1. 七日爆款笔记表格:
- 调用脚本获取数据(最多50条),脚本会自动保存 JSON 到
.cache/目录 - Agent 从脚本输出中提取 JSON 缓存路径(
原始数据已保存到: ...) - 展示TOP1到TOP20(前20条)
- "查看更多"提示逻辑(根据实际数据量动态调整):
- 如果返回数据 ≤ 20条:不展示"查看更多"提示
- 如果返回数据 > 20条且 < 50条:展示"回复"查看更多"可看剩余{实际剩余数量}条!✨"
- 如果返回数据 = 50条:展示"回复"查看更多"可看剩余30条!✨"(固定30条)
2. 功能询问:
- 在七日分析完成后立即展示功能询问(HTML生成 + 订阅服务)
- 等待用户回复后再执行对应操作
3. HTML生成(用户选择后):
- 从第一步自动保存的 JSON 缓存文件读取,禁止再次调用 API
- 执行命令:
python scripts/gen_xhs_html.py --data_file <自动缓存的JSON路径> --category "{分类}" --top 20 - 生成 HTML 文件,文件名格式:
小红书七日爆款笔记_{分类}_{时间戳}.html - 生成后必须立即调用 `preview_url` 展示页面,输出文件路径并自动预览;若未正常展示则用
open_result_view兜底
阶段二:用户输入"查看更多"
1. 七日爆款笔记表格:
- 继续展示TOP21到实际数据末尾(根据实际数据量)
- 延续首次输出的数据,不重复TOP1-20
2. HTML重新生成(如用户选择):
- 从第一步自动缓存的 JSON 文件读取完整数据
- 执行命令:
python scripts/gen_xhs_html.py --data_file <临时JSON文件> --category "{分类}" --top 50 - 覆盖之前的 HTML 文件
数据一致性保障
- 两个脚本使用相同的API接口
- 相同的排序逻辑(互动数优先,备用计算)
- 相同的数据字段和格式
- 确保表格和HTML页面的排名、数据完全一致
操作步骤
标准流程
第一步:分类匹配
根据用户输入自动匹配合适的分类:
可用分类列表(共25个): 综合全部、出行代步、休闲爱好、影视娱乐、数码科技、医疗保健、综合杂项、星座情感、时尚穿搭、婚庆婚礼、拍摄记录、学习教育、化妆美容、居家装修、旅行度假、亲子育儿、个人护理、美味佳肴、职业发展、宠物天地、潮流鞋包、日常生活、科学探索、新闻资讯、体育锻炼
匹配规则:
- 用户输入具体产品词(如"睫毛膏")→ 匹配对应分类("化妆美容")
- 用户输入领域词(如"穿搭"、"美食")→ 直接匹配分类
- 未指定分类 → 使用"综合全部"
关键词-分类映射示例:
睫毛膏/口红/粉底 → 化妆美容
穿搭/衣服/时尚 → 时尚穿搭
美食/做饭/探店 → 美味佳肴
猫/狗/宠物 → 宠物天地
游戏/王者/电竞 → 休闲娱乐第二步:查询冷门爆款笔记
- 用户输入关键词后,自动匹配对应分类(不告知用户匹配到的分类名称)
- 查询该分类下的冷门爆款笔记(最多50条)
- 根据实际数据量动态展示:
- 如果返回数据 ≤ 20条:默认展示全部数据,不展示"查看更多"提示
- 如果返回数据 > 20条:默认展示TOP20,展示"回复"查看更多"可看剩余{数量}条!✨"提示
- 如果返回数据 = 50条:默认展示TOP20,展示"回复"查看更多"可看剩余30条!✨"提示
第三步:日期判断
根据用户输入和当前时间确定查询日期:
判断规则:
1. 用户指定了日期 → 直接使用指定日期 2. 用户未指定日期:
- 当前时间 >= 19:00 → 查询昨日数据(当日19:00已更新)
- 当前时间 < 19:00 → 查询前天数据(等待当日19:00更新)
第四步:获取七日爆款笔记数据
调用脚本获取榜单数据:
python scripts/xhs_weekly_fetcher.py --keyword "睫毛膏" --top_n 50参数详见上方「调用 Key 说明」。
自动保存 JSON 数据:脚本获取数据后会自动将原始 JSON 保存到 .cache/ 目录,并输出保存路径(如 原始数据已保存到: .../xhs_weekly_化妆美容_2026-05-26.json)。Agent 需记住此路径,供后续 HTML 生成使用。
数据完整性要求:
- 确保表格所有字段和数据完整加载
- 如果数据加载失败或字段缺失,必须重新调用脚本再次尝试
- 直到所有字段(排名、笔记信息、互动数、点赞、评论、收藏、分享)都有完整数据
- 分享字段使用正确的API字段名:
AnaAddBean.useShareCount(累计分享数)、AnaAddBean.addShareCount(新增分享数) - 确保分享数值正确输出,避免使用错误的字段名导致数值不对
第五步:输出七日爆款笔记和七日分析
按照输出规范,依次输出:
1. 七日爆款笔记(含更新时间) 2. 七日热门笔记分析(3个模块)
第六步:展示功能询问
重要要求:必须在七日分析输出完成后立即展示,不需要等待用户回复
展示内容:
技能还支持以下功能:
1️⃣ 支持订阅小红书七日爆款笔记。订阅后将在每日19:30为您推送小红书七日爆款笔记TOP50。直接回复"订阅或 1"即可订阅相关内容。
2️⃣ 可生成小红书风格的html文件包。支持导出PDF,方便阅读、保存和分享。回复对应的数字即可。
第七步:用户选择后执行对应操作
用户回复 1 / "订阅":
- 创建每日 19:30 推送的自动化任务
- 推送内容:小红书七日爆款笔记推荐TOP50
用户回复 2 / "html" / "生成":
- 禁止再次调用 API,从已获取的数据文件中读取
- 首次生成(TOP20):
python scripts/gen_xhs_html.py --data_file <临时JSON文件> --category "{分类}" --top 20 - 查看更多后生成(完整数据):
python scripts/gen_xhs_html.py --data_file <临时JSON文件> --category "{分类}" --top 50 - HTML 文件名格式:
小红书七日爆款笔记_{分类}_{唯一时间戳}.html - HTML 生成后必须立即调用 `preview_url` 直接展示页面,让用户无需手动查找文件即可浏览报告
输出格式:
HTML 生成后,Agent 必须执行以下步骤: 1. 优先调用 preview_url 工具直接展示 HTML 页面,让用户在对话中即可浏览完整报告 2. 若 preview_url 未能正常展示(用户反馈看不到),立即改用 open_result_view 兜底展示 3. 同时输出文件路径,方便用户后续查找
📁 HTML文件包已生成 路径:/path/to/小红书七日爆款笔记_综合_20260528160530.html订阅服务说明
订阅内容
小红书七日热门笔记推荐TOP50
- 每日19:30更新
- 推送往前7天的50篇热门内容
- 包含完整分析和HTML文件
订阅输出格式
📅 小红书七日热门笔记推荐(2026-04-15 19:30每日更新往前7天的50篇内容)
🔥 【综合全部】七日爆款笔记 (更新时间:2026-04-15 19:30:00)
| 排名 | 笔记信息 | 互动数 | 点赞 | 评论 | 收藏 | 分享 |
|---|---|---|---|---|---|---|
| 🥇 | [笔记标题链接]<br>作者名 粉丝数+ | 8w+<br>↑新增1w+ | 5w+<br>↑新增5000+ | 2w+<br>↑新增2000+ | 1w+<br>↑新增1000+ | 800+<br>↑新增500+ |
回复"查看更多"可看剩余30条!✨
📊 七日热门笔记分析(Top50)
以下内容分析基于获取的全部数据(Top50)进行~
💡热门内容分析
| 内容分类 | 内容特征 | 实际效果 | 参考笔记 |
|---|---|---|---|
| 封面设计 | 采用高清摄影或设计软件精心制作的封面图,画面构图饱满、色彩搭配协调,同时加入醒目的文字标题或标签,突出核心卖点或吸引眼球的元素,通过强烈的视觉冲击力在用户快速浏览时瞬间抓住注意力 | 点击率提升45% | [笔记标题链接1]<br>[笔记标题链接2] |
| 内容创作 | 围绕用户痛点或情感共鸣点展开叙事,采用第一人称视角分享真实经历或心得,结合表情符号和分段排版增强可读性,适当设置悬念或反转,激发用户的情感共鸣和参与欲望 | 互动率提升50% | [笔记标题链接3]<br>[笔记标题链接4] |
| 内容价值 | 提供具体可操作的步骤、方法或技巧,配合清晰的图片展示和简明的文字说明,确保用户看完后能够直接复用或实践,内容具有较高的实用价值和参考意义,值得用户收藏备查 | 收藏率提升55% | [笔记标题链接5]<br>[笔记标题链接6] |
| 热点结合 | 紧跟当前热门话题、节日或社会热点,将自身内容与热点元素巧妙结合,使用相关话题标签增加曝光机会,借助热点的流量优势快速提升笔记的传播范围和影响力 | 曝光率提升40% | [笔记标题链接7]<br>[笔记标题链接8] |
📈爆款标题分析
| 标题类型 | 标题特征 | 标题模版 | 发布规律 | 参考标题 |
|---|---|---|---|---|
| 提问式 | 标题以疑问句开头,设置悬念或提出用户关心的问题,引发用户的好奇心和思考欲望,激发点击阅读或评论互动 | "你还在XX吗?" | 工作日早高峰效果最佳 | 这个方法你还在用吗? |
| 数字式 | 标题中包含具体的数字、数量或统计数据,利用人们对量化信息的偏好,增强内容的可信度和专业感,让用户觉得内容有价值 | "XX个XX技巧" | 午餐时间点击率高 | 5个快速提升XX的技巧 |
| 情绪词 | 使用具有强烈情感色彩的词汇或网络流行语,如"绝了"、"太XX了"等,直接触发用户的情绪反应,引发点赞、评论或分享行为 | "太XX了!忍不住" | 晚间黄金时段转化高 | 太好用了!忍不住分享给你 |
| 利益点 | 直接在标题中明确承诺用户可以获得的具体利益或效果,如"XX天就能XX"、"省XX元"等,降低用户决策成本,提高点击率和收藏率 | "XX天就能XX" | 深夜发布收藏率最高 | 7天就能看到明显效果 |
✨最高数据作品分析
| 维度 | 核心特征分析 | 参考笔记 |
|---|---|---|
| 最高点赞 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
| 最高收藏 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
| 最高评论 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
| 最高互动 | 风格:具体风格描述<br>特征:详细特征说明<br>数据效果:效果数据<br>建议:具体建议 | [笔记标题链接] |
📁 HTML文件包
**订阅服务(是否需要订阅小红书七日热门笔记推荐?)**
1. 每日19:30-推送小红书七日热门笔记TOP50
2. 暂不需要-仅本次查询
请回复数字或"取消"。
## 使用示例
### 示例1:关键词查询(数据=50条)
- **场景/输入**:"帮我查一下睫毛膏相关的爆款笔记"
- **执行流程**:
1. 匹配分类:睫毛膏 → 化妆美容
2. 查询化妆美容分类,返回50条数据,保存JSON到临时文件
3. 七日爆款笔记表格展示TOP1-20
4. 展示"回复"查看更多"可看剩余30条!✨"提示
5. 输出完整分析(热门内容分析、爆款标题分析、最高数据作品分析)
6. **展示功能询问**(HTML生成 + 订阅服务)
7. 用户选择后执行对应操作(HTML从临时JSON文件读取,不再调用API)
### 示例2:泛查询热门内容(数据=30条)
- **场景/输入**:"最近小红书有什么热门内容"
- **执行流程**:
1. 使用"综合全部"分类
2. 查询后返回30条数据,保存JSON到临时文件
3. 七日爆款笔记表格展示TOP1-20
4. 展示"回复"查看更多"可看剩余10条!✨"提示
5. 输出完整分析(热门内容分析、爆款标题分析、最高数据作品分析)
6. **展示功能询问**(HTML生成 + 订阅服务)
### 示例3:数据不足20条(数据=15条)
- **场景/输入**:"查询某个冷门分类"
- **执行流程**:
1. 匹配对应分类
2. 查询后返回15条数据,保存JSON到临时文件
3. 七日爆款笔记表格展示TOP1-15(全部数据)
4. 不展示"查看更多"提示(数据未超过20条)
5. 输出完整分析(热门内容分析、爆款标题分析、最高数据作品分析)
6. **展示功能询问**(HTML生成 + 订阅服务)
### 示例4:查看更多内容
- **场景/输入**:用户回复"查看更多"
- **执行流程**:
1. 七日爆款笔记表格展示TOP21-实际数据末尾(延续之前的数据)
2. 如用户选择生成HTML,从临时JSON文件读取完整数据重新生成
## 资源索引
- **脚本**:见 [scripts/xhs_weekly_fetcher.py](scripts/xhs_weekly_fetcher.py)
- 用途:获取小红书七日爆款笔记数据
- 参数:详见上方「调用 Key 说明」
- **脚本**:见 [scripts/gen_xhs_html.py](scripts/gen_xhs_html.py)
- 用途:生成可视化HTML页面
- 参数:详见上方「调用 Key 说明」
## 注意事项
- 数据每日19:00更新昨天的榜单
- **输出内容(强制,禁止遗漏,禁止胡乱输出)**:必须严格包含七日爆款笔记(更新时间)+ 七日热门笔记分析 + 功能询问
- 🔥 七日爆款笔记(必须包含更新时间)
- 📊 七日热门笔记分析(3个模块:热门内容分析、爆款标题分析、最高数据作品分析)
- 功能询问(HTML生成 + 订阅服务,分析完成后立即展示)
- **禁止输出遗漏,禁止胡乱输出,必须严格按照此3项内容输出**
- **输出格式要求(强制)**:
- **禁止折叠输出**:所有内容必须直接完整输出,禁止使用折叠、隐藏、展开等任何形式的折叠输出
- **禁止输出文件**:除HTML文件包外,禁止输出任何其他文件(如CSV、JSON、TXT等)
- **输出顺序**:严格按照七日爆款笔记 → 七日分析 → HTML文件包 → 订阅服务的顺序执行,禁止混乱输出
- **输出顺序(严格按此顺序执行,禁止混乱输出)**:
1. **🔥 七日爆款笔记**(含更新时间,展示互动数/点赞/评论/收藏及新增数据,**不显示匹配到的分类名称**)
2. **📊 七日热门笔记分析**(💡热门内容分析、📈爆款标题分析、✨最高数据作品分析)
3. **功能询问**(必须在分析之后展示,提供HTML生成和订阅推送选项)
- **HTML文件包输出要求(强制)**:
- 必须在用户选择生成后才执行,不得自动生成
- **禁止再次调用 API**,必须从已获取的数据文件中读取
- HTML 文件名格式:`小红书七日爆款笔记_{分类}_{唯一时间戳}.html`
- **生成后必须立即调用 `preview_url` 在对话中直接展示页面**,禁止只输出文件路径
- **若 `preview_url` 未正常展示(含中文路径等兼容问题),立即改用 `open_result_view` 兜底**
- **PDF和图片导出内容一定是正确的**
- **功能询问输出要求(强制,必须执行)**:
- 必须在七日分析输出完成后立即展示
- **禁止跳过,禁止遗漏,禁止等待用户回复**
- 提供两个选项:订阅推送 或 生成HTML文件包
- 用户可回复数字或关键词选择对应功能
- **数据一致性要求**:七日爆款笔记表格与HTML页面必须使用相同的数据源和排序逻辑,确保完全一致
- **数据完整性要求(强制)**:
- 表格所有字段和数据必须完整加载
- 如果数据加载失败或字段缺失,必须重新调用脚本再次尝试
- 直到所有字段都有完整数据(七日爆款笔记7个字段、七日分析所有表格字段)
- **数据输出逻辑(必须严格执行)**:
- 首次输出:七日爆款笔记TOP1-20,HTML页面TOP1-20(保持一致)
- 查看更多:七日爆款笔记TOP21-实际数据末尾,HTML页面TOP1-实际数据末尾(完整数据)
- **"查看更多"提示逻辑**:
- 数据 ≤ 20条:不展示
- 数据 > 20条且 < 50条:展示"回复"查看更多"可看剩余{数量}条!✨"
- 数据 = 50条:展示"回复"查看更多"可看剩余30条!✨"
- 表格字段:排名、笔记信息、互动数(新增互动)、点赞(新增点赞)、评论(新增评论)、收藏(新增收藏)、分享(新增分享,**必须展示且不能出错,避免胡乱输出**)
- 七日分析包含:热门内容分析、爆款标题分析、最高数据作品分析
- 七日分析标题后显示"以下内容分析基于获取的全部数据(Top{数据条数})进行~"
- 分析内容从创作者视角出发,提供可执行建议
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
小红书七日爆款笔记HTML生成器
从已获取的JSON数据文件读取数据,生成可独立打开的HTML页面。
用法:python gen_xhs_html.py --data_file <JSON数据文件> --category "分类名" --top N [--output PATH]
输出:小红书七日爆款笔记_{分类}_{时间戳}.html(与脚本同目录)
样式特性:
- 小红书风格(红色主题 #ff2442)
- 卡片式布局,多行展示
- 标题和作者在第一行,数据在第二行
- TOP3 奖牌徽章 + 左边框高亮
- 导出 PDF 功能
- 页面最大宽度 750px
"""
import json
import sys
import os
from datetime import datetime
def clean_text(text: str) -> str:
"""
清理文本中的特殊字符,用于表格单元格显示
清理内容:
- 空格
- 换行符(\r, \n)
- URL链接
- Image标记
- 特殊字符(<>{}[]|\)
"""
import re
if not text:
return ""
text = str(text)
# 移除URL
text = re.sub(r'https?://\S+', '', text)
# 移除Image标记
text = re.sub(r'Image:\s*\[.*?\]', '', text)
# 移除换行符
text = re.sub(r'[\r\n]+', '', text)
# 移除空格
text = text.replace(' ', '')
# 移除特殊字符
text = re.sub(r'[<>{}[\]\\|]', '', text)
return text.strip()
def load_data_from_file(data_file: str) -> list:
"""
从JSON数据文件加载笔记数据
支持两种格式:
1. {"hot_list": [...]} - xhs_weekly_fetcher.py 输出格式
2. [...] - 纯列表格式
Args:
data_file: JSON数据文件路径
Returns:
笔记数据列表
"""
with open(data_file, 'r', encoding='utf-8') as f:
data = json.load(f)
if isinstance(data, list):
return data
elif isinstance(data, dict):
# 尝试从常见字段提取
for key in ['hot_list', 'data', 'list', 'articles']:
if key in data and isinstance(data[key], list):
return data[key]
# 如果都没有,返回空
return []
return []
def generate_html(hot_list: list, category: str = "综合全部", top_n: int = 20) -> str:
"""生成HTML页面 - 小红书风格
Args:
hot_list: 笔记数据列表
category: 分类名称
top_n: 显示条数,默认20
重要:只传递实际需要展示的数据到HTML,确保统计数据与展示数据一致
"""
fetch_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 限制显示条数 - 必须先截取,确保统计数据准确
top_n = min(top_n, len(hot_list), 50) # 最大支持TOP50
hot_list = hot_list[:top_n]
js_data = json.dumps(hot_list, ensure_ascii=False, indent=2)
page_title = f"小红书七日爆款笔记 - {category}"
html = f'''<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{page_title}</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
<style>
* {{ margin: 0; padding: 0; box-sizing: border-box; }}
body {{
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'PingFang SC', sans-serif;
background: #f5f5f5;
color: #333;
line-height: 1.5;
}}
.page-wrap {{
max-width: 700px;
margin: 0 auto;
padding: 12px 12px 24px;
}}
.export-bar {{
position: sticky;
top: 0;
z-index: 100;
display: flex;
justify-content: flex-end;
gap: 10px;
padding: 8px 0 10px;
}}
.btn-export-pdf, .btn-export-img {{
background: #fff;
color: #ff2442;
border: 1.5px solid #ff2442;
border-radius: 20px;
padding: 6px 18px;
font-size: 13px;
font-weight: 600;
cursor: pointer;
transition: all 0.2s ease;
}}
.btn-export-pdf:hover, .btn-export-img:hover {{ background: #fff5f6; }}
.pdf-content {{ background: transparent; }}
.header-wrap {{
background: linear-gradient(135deg, #ff2442 0%, #ff6b81 100%);
border-radius: 12px;
padding: 20px 16px;
margin-bottom: 12px;
color: #fff;
}}
.header-wrap h1 {{
font-size: 22px;
font-weight: 700;
margin-bottom: 4px;
}}
.header-meta {{
font-size: 13px;
opacity: 0.9;
}}
.category-badge {{
display: inline-block;
background: rgba(255,255,255,0.25);
border-radius: 10px;
padding: 2px 10px;
font-size: 13px;
margin-left: 8px;
}}
.stats-row {{
display: flex;
justify-content: space-around;
margin-top: 14px;
padding-top: 14px;
border-top: 1px solid rgba(255,255,255,0.2);
}}
.stat-item {{
text-align: center;
}}
.stat-num {{
font-size: 20px;
font-weight: 700;
}}
.stat-label {{
font-size: 12px;
opacity: 0.85;
margin-top: 2px;
}}
.note-list {{
display: flex;
flex-direction: column;
gap: 10px;
}}
.note-card {{
background: #fff;
border-radius: 12px;
padding: 14px;
cursor: pointer;
transition: all 0.2s ease;
border: 1px solid #f0f0f0;
}}
.note-card:hover {{
box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}}
.note-card.top1 {{ border-left: 3px solid #ff2442; }}
.note-card.top2 {{ border-left: 3px solid #ff6b81; }}
.note-card.top3 {{ border-left: 3px solid #ffb3c1; }}
.note-row1 {{
display: flex;
align-items: flex-start;
margin-bottom: 10px;
}}
.rank-num {{
min-width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
font-weight: 700;
color: #999;
margin-right: 12px;
flex-shrink: 0;
}}
.note-info {{
flex: 1;
min-width: 0;
}}
.note-title {{
font-size: 16px;
font-weight: 600;
color: #333;
line-height: 1.4;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
margin-bottom: 8px;
}}
.note-title a {{
color: #333;
text-decoration: none;
}}
.note-title a:hover {{
color: #ff2442;
}}
.author-info {{
display: flex;
align-items: center;
gap: 6px;
font-size: 13px;
color: #999;
}}
.author-avatar {{
width: 22px;
height: 22px;
border-radius: 50%;
object-fit: cover;
}}
.author-name {{
color: #666;
}}
.fans-count {{
color: #999;
}}
.note-row2 {{
display: flex;
flex-wrap: wrap;
gap: 14px;
padding-left: 48px;
/* 48px = rank-num宽度36px + margin-right 12px,与头像边界对齐 */
}}
.data-item {{
display: flex;
align-items: center;
gap: 4px;
font-size: 13px;
}}
.data-label {{
color: #999;
}}
.data-value {{
color: #333;
font-weight: 600;
}}
.data-add {{
color: #ff2442;
font-size: 12px;
margin-left: 4px;
}}
.footer-note {{
text-align: center;
font-size: 12px;
color: #bbb;
margin-top: 16px;
padding: 10px 0;
}}
@media (max-width: 600px) {{
.page-wrap {{ padding: 8px 8px 20px; }}
.header-wrap {{ padding: 16px 12px; }}
.header-wrap h1 {{ font-size: 20px; }}
.note-card {{ padding: 12px; }}
.note-title {{ font-size: 15px; }}
.rank-num {{ min-width: 32px; height: 32px; font-size: 16px; }}
.note-row2 {{ gap: 10px; padding-left: 44px; margin-top: 8px; }}
.data-item {{ font-size: 12px; }}
}}
</style>
</head>
<body>
<div class="page-wrap">
<div class="export-bar">
<button class="btn-export-img" onclick="exportImage()">导出图片</button>
<button class="btn-export-pdf" onclick="exportPdf()">导出 PDF</button>
</div>
<div class="pdf-content" id="pdfContent">
<div class="header-wrap">
<h1>📱 小红书七日爆款笔记<span class="category-badge">{category}</span></h1>
<div class="header-meta">更新时间:{fetch_time}</div>
<div class="stats-row">
<div class="stat-item">
<div class="stat-num" id="totalCount">--</div>
<div class="stat-label">笔记总数</div>
</div>
<div class="stat-item">
<div class="stat-num" id="maxInteractive">--</div>
<div class="stat-label">最高互动</div>
</div>
<div class="stat-item">
<div class="stat-num" id="avgInteractive">--</div>
<div class="stat-label">平均互动</div>
</div>
</div>
</div>
<div class="note-list" id="noteList"></div>
<div class="footer-note">数据来源:小红书平台 · {category} · 七日爆款笔记排行</div>
</div>
</div>
<script>
(function() {{
function bindCardClick() {{
var cards = document.querySelectorAll('.note-card[data-href]');
cards.forEach(function(card) {{
card.addEventListener('click', function(e) {{
if (e.target.closest('a, button')) return;
var url = this.getAttribute('data-href');
if (url && url !== '#') window.open(url, '_blank');
}});
}});
}}
if (document.readyState === 'loading') {{
document.addEventListener('DOMContentLoaded', bindCardClick);
}} else {{
bindCardClick();
}}
}})();
(function() {{
var RAW = {js_data};
var totalCount = RAW.length;
var maxInteractive = 0, sumInteractive = 0;
function parseInteractive(val) {{
if (typeof val === 'string') {{
if (val.indexOf('w') !== -1 || val.indexOf('W') !== -1) {{
return parseFloat(val) * 10000;
}} else if (val.indexOf('亿') !== -1) {{
return parseFloat(val) * 100000000;
}}
return parseFloat(val) || 0;
}}
return val || 0;
}}
function fmtNum(val) {{
if (typeof val === 'string') {{
if (val.indexOf('w') !== -1 || val.indexOf('W') !== -1 || val.indexOf('亿') !== -1) {{
return val;
}}
}}
var n = parseInt(val) || 0;
if (n >= 10000) {{
return (n / 10000).toFixed(1) + 'w';
}}
return n.toString();
}}
for (var i = 0; i < RAW.length; i++) {{
var interactive = parseInteractive(RAW[i].interactiveCount);
if (interactive > maxInteractive) maxInteractive = interactive;
sumInteractive += interactive;
}}
var avgInteractive = totalCount > 0 ? sumInteractive / totalCount : 0;
document.getElementById('totalCount').textContent = totalCount;
document.getElementById('maxInteractive').textContent = fmtNum(maxInteractive);
document.getElementById('avgInteractive').textContent = fmtNum(Math.round(avgInteractive));
var html = '';
for (var i = 0; i < RAW.length && i < {top_n}; i++) {{
var d = RAW[i];
var rank = i + 1;
var cardCls = 'note-card';
if (rank === 1) cardCls += ' top1';
else if (rank === 2) cardCls += ' top2';
else if (rank === 3) cardCls += ' top3';
var noteUrl = (d.photoJumpUrl || '#').replace(/ /g, '%20');
var avatar = d.userHeadUrl || '';
var userName = (d.userName || '--').replace(/ /g, '');
var fans = (d.fans || '').replace(/ /g, '');
var title = (d.title || '--').replace(/ /g, '');
var interactive = (d.interactiveCount || '0').replace(/ /g, '');
var addInteractive = (d.addInteractiveount || '0').replace(/ /g, '');
var likeCount = (d.useLikeCount || '0').replace(/ /g, '');
var addLikeCount = (d.addLikeCount || '0').replace(/ /g, '');
var commentCount = (d.useCommentCount || '0').replace(/ /g, '');
var addCommentCount = (d.addCommentCount || '0').replace(/ /g, '');
var collected = (d.collectedCount || '0').replace(/ /g, '');
var addCollected = (d.addCollectedCunt || '0').replace(/ /g, '');
var shareCount = (d.useShareCount || '0').replace(/ /g, '');
var addShareCount = (d.addShareCount || '0').replace(/ /g, '');
var rankHtml = '';
if (rank === 1) {{
rankHtml = '<div class="rank-num">🥇</div>';
}} else if (rank === 2) {{
rankHtml = '<div class="rank-num">🥈</div>';
}} else if (rank === 3) {{
rankHtml = '<div class="rank-num">🥉</div>';
}} else {{
rankHtml = '<div class="rank-num">' + rank + '</div>';
}}
html += '<div class="' + cardCls + '" data-href="' + noteUrl + '">'
+ '<div class="note-row1">'
+ rankHtml
+ '<div class="note-info">'
+ '<div class="note-title"><a href="' + noteUrl + '" target="_blank" onclick="event.stopPropagation()">' + title + '</a></div>'
+ '<div class="author-info">'
+ (avatar ? '<img class="author-avatar" src="' + avatar + '" onerror="this.style.display=\\'none\\'">' : '')
+ '<span class="author-name">' + userName + '</span>'
+ (fans ? '<span class="fans-count">·' + fans + '粉丝</span>' : '')
+ '</div>'
+ '</div>'
+ '</div>'
+ '<div class="note-row2">'
+ '<div class="data-item"><span class="data-label">互动</span><span class="data-value">' + fmtNum(interactive) + '</span><span class="data-add">↑' + fmtNum(addInteractive) + '</span></div>'
+ '<div class="data-item"><span class="data-label">点赞</span><span class="data-value">' + fmtNum(likeCount) + '</span><span class="data-add">↑' + fmtNum(addLikeCount) + '</span></div>'
+ '<div class="data-item"><span class="data-label">评论</span><span class="data-value">' + fmtNum(commentCount) + '</span><span class="data-add">↑' + fmtNum(addCommentCount) + '</span></div>'
+ '<div class="data-item"><span class="data-label">收藏</span><span class="data-value">' + fmtNum(collected) + '</span><span class="data-add">↑' + fmtNum(addCollected) + '</span></div>'
+ '<div class="data-item"><span class="data-label">分享</span><span class="data-value">' + fmtNum(shareCount) + '</span><span class="data-add">↑' + fmtNum(addShareCount) + '</span></div>'
+ '</div>'
+ '</div>';
}}
document.getElementById('noteList').innerHTML = html;
}})();
function exportImage() {{
var btn = document.querySelector('.btn-export-img');
btn.textContent = '生成中...';
btn.style.pointerEvents = 'none';
var target = document.getElementById('pdfContent');
html2canvas(target, {{
scale: 2,
useCORS: true,
backgroundColor: '#f5f5f5',
logging: false,
windowWidth: target.scrollWidth,
windowHeight: target.scrollHeight
}}).then(function(canvas) {{
var link = document.createElement('a');
link.download = '小红书七日爆款笔记_' + new Date().toISOString().slice(0,10) + '.png';
link.href = canvas.toDataURL('image/png');
link.click();
btn.textContent = '导出图片';
btn.style.pointerEvents = '';
}}).catch(function(err) {{
alert('图片生成失败:' + err.message);
btn.textContent = '导出图片';
btn.style.pointerEvents = '';
}});
}}
function exportPdf() {{
var btn = document.querySelector('.btn-export-pdf');
btn.textContent = '生成中...';
btn.style.pointerEvents = 'none';
var target = document.getElementById('pdfContent');
html2canvas(target, {{
scale: 2,
useCORS: true,
backgroundColor: '#f5f5f5',
logging: false,
windowWidth: target.scrollWidth,
windowHeight: target.scrollHeight
}}).then(function(canvas) {{
var imgData = canvas.toDataURL('image/png', 1.0);
// 使用横向 A4 纸
var pdf = new jspdf.jsPDF('l', 'mm', 'a4');
var pdfW = pdf.internal.pageSize.getWidth();
var pdfH = pdf.internal.pageSize.getHeight();
var margin = 8;
var contentW = pdfW - margin * 2;
var contentH = pdfH - margin * 2;
// 计算图片尺寸以适应横向 A4
var imgW = contentW;
var imgH = (canvas.height * imgW) / canvas.width;
// 如果高度仍然超过页面高度,按高度缩放
if (imgH > contentH) {{
imgH = contentH;
imgW = (canvas.width * imgH) / canvas.height;
}}
// 居中显示
var imgX = (pdfW - imgW) / 2;
var imgY = (pdfH - imgH) / 2;
// 所有内容在一页中
pdf.addImage(imgData, 'PNG', imgX, imgY, imgW, imgH);
var now = new Date();
var dateStr = now.getFullYear() +
String(now.getMonth()+1).padStart(2,'0') +
String(now.getDate()).padStart(2,'0') +
'_' +
String(now.getHours()).padStart(2,'0') +
String(now.getMinutes()).padStart(2,'0');
pdf.save('小红书七日爆款笔记_' + dateStr + '.pdf');
btn.textContent = '导出 PDF';
btn.style.pointerEvents = '';
}}).catch(function(err) {{
alert('PDF 生成失败:' + err.message);
btn.textContent = '导出 PDF';
btn.style.pointerEvents = '';
}});
}}
</script>
</body>
</html>'''
# Replace js_data placeholder
html = html.replace("{js_data}", js_data)
return html
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description='生成小红书七日爆款笔记HTML页面')
parser.add_argument('--data_file', type=str, required=True, help='已获取的JSON数据文件路径')
parser.add_argument('--category', type=str, default='综合全部', help='分类名称')
parser.add_argument('--keyword', type=str, help='用户输入的关键词(仅用于兼容,不影响数据读取)')
parser.add_argument('--output', type=str, help='输出文件路径')
parser.add_argument('--top', type=int, default=20, help='显示条数,默认20,可设为50')
args = parser.parse_args()
# 检查数据文件是否存在
if not os.path.isfile(args.data_file):
print(f"错误:数据文件不存在 - {args.data_file}", file=sys.stderr)
sys.exit(1)
# 从JSON文件加载数据(不再调用API)
print(f"从数据文件加载数据: {args.data_file}", file=sys.stderr)
hot_list = load_data_from_file(args.data_file)
if not hot_list:
print("错误:数据文件为空或格式不正确", file=sys.stderr)
sys.exit(1)
category = args.category
print(f"分类:{category}", file=sys.stderr)
print(f"共加载 {len(hot_list)} 条数据,展示TOP{args.top}", file=sys.stderr)
# 生成HTML
html = generate_html(hot_list, category=category, top_n=args.top)
# 确定输出路径
if args.output:
output_path = args.output
else:
# 生成唯一时间戳文件名
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
safe_category = category.replace("/", "_").replace("\\", "_")
filename = f"小红书七日爆款笔记_{safe_category}_{timestamp}.html"
output_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), filename)
with open(output_path, 'w', encoding='utf-8') as f:
f.write(html)
print(f"已生成:{output_path}", file=sys.stderr)
print(f"共 {len(hot_list)} 条数据,展示TOP{args.top}", file=sys.stderr)
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
小红书七日爆款笔记获取脚本
功能:
1. 调用API获取小红书七日爆款笔记数据
2. 按互动数排序
3. 输出TOP30榜单列表(纯文本格式)
4. 提供三维度内容分析(数据表现、内容结构、选题价值)
使用方法:
python fetch_explosive_articles.py --rank_date "2026-04-15" --category "时尚穿搭"
"""
import argparse
import json
import os
import sys
from datetime import datetime, timedelta
from urllib.parse import quote
import requests
def get_api_key() -> str:
"""
获取 REDFOX_API_KEY
三级认证回退机制:
1. 从当前设备环境变量 REDFOX_API_KEY 中获取
2. 若未获取到,自动从 shell 配置文件中读取
3. 仍然没有则提示用户配置
Returns:
API Key 字符串
Raises:
ValueError: 未找到 API Key 时抛出,附带配置指引
"""
import platform
import re as re_mod
# 第一级:环境变量
api_key = os.environ.get("REDFOX_API_KEY", "").strip()
if api_key:
return api_key
# 第二级:Shell 配置文件
home = os.path.expanduser("~")
config_files = []
if platform.system() == "Windows":
config_files = [
os.path.join(home, "Documents", "WindowsPowerShell", "Microsoft.PowerShell_profile.ps1"),
os.path.join(home, "Documents", "PowerShell", "Microsoft.PowerShell_profile.ps1"),
]
else:
config_files = [
os.path.join(home, ".zshrc"),
os.path.join(home, ".bashrc"),
os.path.join(home, ".bash_profile"),
os.path.join(home, ".profile"),
]
for cf in config_files:
if os.path.isfile(cf):
try:
with open(cf, "r", encoding="utf-8", errors="ignore") as f:
content = f.read()
match = re_mod.search(
r'REDFOX_API_KEY\s*[=:]\s*["\']?([a-zA-Z0-9_\-]+)["\']?',
content
)
if match:
return match.group(1).strip()
except Exception:
continue
# 第三级:提示用户配置
raise ValueError(
"未找到 REDFOX_API_KEY。请按以下步骤配置:\n"
"1. 访问 https://redfox.hk/login 注册并获取 API Key\n"
"2. 设置环境变量:\n"
" macOS/Linux: export REDFOX_API_KEY=<你的apikey>\n"
" Windows PowerShell: [Environment]::SetEnvironmentVariable('REDFOX_API_KEY', '<值>', 'User')\n"
"3. 配置后重启终端使其生效"
)
def get_query_date(user_date: str = None) -> tuple:
"""
根据用户输入和当前时间确定查询日期
规则:
1. 用户指定了日期 → 直接使用
2. 未指定日期:
- 当前时间 >= 19:00 → 查询昨日数据(当日19:00已更新)
- 当前时间 < 19:00 → 查询前天数据(等待当日19:00更新)
Args:
user_date: 用户指定的日期(格式:yyyy-MM-dd)
Returns:
(查询日期, 是否为自动推断)
"""
if user_date:
return user_date, False
now = datetime.now()
cutoff_time = now.replace(hour=19, minute=0, second=0, microsecond=0)
if now >= cutoff_time:
# 超过19:00,查询昨日(当日已更新)
query_date = (now - timedelta(days=1)).strftime("%Y-%m-%d")
else:
# 未超过19:00,查询前天(等待当日更新)
query_date = (now - timedelta(days=2)).strftime("%Y-%m-%d")
return query_date, True
# 分类关键词映射(包含产品词映射)
CATEGORY_KEYWORDS = {
"综合全部": ["综合", "全部", "热门", "推荐", "随便", "随便看看", "总榜", "整体"],
"出行代步": ["出行", "代步", "交通", "汽车", "打车", "地铁", "公交", "开车", "驾车", "出行方式", "通勤", "自驾", "新能源车", "电动车"],
"休闲爱好": ["休闲", "爱好", "兴趣", "娱乐", "休闲活动", "兴趣爱", "业余", "消遣", "手工", "DIY", "收藏"],
"影视娱乐": ["影视", "娱乐", "电影", "电视剧", "综艺", "明星", "追剧", "看剧", "演员", "导演", "剧集", "追星", "综艺"],
"数码科技": ["数码", "科技", "手机", "电脑", "数码产品", "科技产品", "智能", "电子", "硬件", "软件", "app", "APP", "iPhone", "安卓", "平板", "耳机", "键盘", "鼠标"],
"医疗保健": ["医疗", "保健", "健康", "医院", "医生", "看病", "养生", "保健", "体检", "治疗", "药品", "中医", "减肥", "瘦身"],
"综合杂项": ["杂项", "其他", "综合杂项", "杂货", "综合类"],
"星座情感": ["星座", "情感", "爱情", "恋爱", "感情", "星座运势", "情感咨询", "脱单", "表白", "分手", "复合", "塔罗", "占卜"],
"时尚穿搭": ["时尚", "穿搭", "衣服", "服装", "搭配", "穿衣", "时装", "潮流穿搭", "服饰", "OOTD", "ootd", "裙子", "裤子", "外套", "大衣", "西装", "毛衣", "T恤"],
"婚庆婚礼": ["婚庆", "婚礼", "结婚", "婚纱", "婚宴", "求婚", "订婚", "婚庆策划", "新娘", "新郎", "伴娘", "钻戒"],
"拍摄记录": ["拍摄", "记录", "摄影", "拍照", "照片", "视频", "vlog", "Vlog", "VLOG", "摄像", "短视频", "相机", "镜头"],
"学习教育": ["学习", "教育", "培训", "课程", "考试", "学校", "教育机构", "学习方法", "考研", "考公", "留学", "英语", "编程", "技能"],
"化妆美容": ["化妆", "美容", "美妆", "妆容", "护肤", "彩妆", "化妆品", "美容护肤", "化妆教程", "美颜", "睫毛膏", "口红", "粉底", "眉笔", "眼影", "腮红", "遮瑕", "定妆", "精华", "面霜", "水乳", "防晒", "面膜"],
"居家装修": ["居家", "装修", "家居", "家装", "房子装修", "室内设计", "软装", "硬装", "家居好物", "家具", "收纳", "整理"],
"旅行度假": ["旅行", "度假", "旅游", "出游", "旅行攻略", "景点", "旅游攻略", "自由行", "跟团游", "自驾游", "酒店", "民宿"],
"亲子育儿": ["亲子", "育儿", "宝宝", "儿童", "带娃", "育儿经", "亲子活动", "母婴", "幼儿", "小孩", "奶粉", "尿布", "玩具"],
"个人护理": ["个人护理", "护理", "护肤", "身体护理", "美容护理", "护理产品", "个人清洁", "洗发水", "沐浴露", "牙膏", "卫生巾"],
"美味佳肴": ["美味", "佳肴", "美食", "做饭", "烹饪", "菜谱", "美食推荐", "餐厅", "探店", "食谱", "好吃", "甜品", "烘焙", "奶茶", "咖啡", "零食"],
"职业发展": ["职业", "发展", "工作", "职场", "求职", "面试", "职业规划", "跳槽", "升职", "加薪", "简历", "副业", "创业"],
"宠物天地": ["宠物", "猫", "狗", "养猫", "养狗", "萌宠", "宠物猫", "宠物狗", "铲屎官", "喵星人", "汪星人", "猫粮", "狗粮"],
"潮流鞋包": ["潮流", "鞋包", "鞋子", "包包", "潮鞋", "名牌包", "运动鞋", "高跟鞋", "手提包", "球鞋", "帆布鞋", "靴子"],
"日常生活": ["日常", "生活", "日常记录", "生活日常", "vlog日常", "生活分享", "好物推荐"],
"科学探索": ["科学", "探索", "科普", "科学知识", "实验", "发现", "研究", "科技探索"],
"新闻资讯": ["新闻", "资讯", "热点", "时事", "新闻报道", "新闻资讯", "最新消息"],
"体育锻炼": ["体育", "锻炼", "运动", "健身", "减肥", "瘦身", "体育运动", "健身房", "瑜伽", "跑步", "游泳", "篮球", "足球"],
}
def match_category(user_input: str) -> str:
"""
根据用户输入匹配分类
Args:
user_input: 用户输入的关键词或描述
Returns:
匹配的分类名称,默认返回"综合全部"
"""
if not user_input:
return "综合全部"
user_input = user_input.lower().strip()
# 遍历分类关键词进行匹配
for category, keywords in CATEGORY_KEYWORDS.items():
for keyword in keywords:
if keyword.lower() in user_input:
return category
# 如果没有匹配到,返回综合全部
return "综合全部"
def get_all_categories():
"""获取所有分类列表"""
return list(CATEGORY_KEYWORDS.keys())
def fetch_explosive_articles(rank_date: str, category: str = "综合全部") -> dict:
"""
调用API获取小红书七日爆款笔记数据(使用原生 requests)
Args:
rank_date: 日期(格式:yyyy-MM-dd)
category: 分类名称(默认:综合全部)
Returns:
API返回的数据
"""
credential = get_api_key()
source = quote("小红书七日数据爆款文章-GitHub")
category_encoded = quote(category)
url = f"https://redfox.hk/story/api/cozeSkill/getXhsCozeSkillDataSeven?rankDate={rank_date}&source={source}&category={category_encoded}"
headers = {
"Content-Type": "application/json",
"X-API-KEY": credential
}
try:
response = requests.get(url, headers=headers, timeout=30)
if response.status_code >= 400:
raise Exception(f"HTTP请求失败: {response.status_code}, {response.text}")
data = response.json()
# 检查API返回的错误信息(成功码为2000)
if "code" in data and data["code"] != 2000:
error_msg = data.get("msg", data.get("message", "未知错误"))
raise Exception(f"API错误: {error_msg}")
return data
except requests.exceptions.RequestException as e:
raise Exception(f"请求失败: {str(e)}")
except json.JSONDecodeError as e:
raise Exception(f"JSON解析失败: {str(e)}")
def process_ranking_data(data: dict, top_n: int = 10) -> list:
"""
处理榜单数据,按互动数排序
Args:
data: API返回的原始数据
top_n: 返回前N条数据(默认10条)
Returns:
排序后的榜单列表
"""
# 提取笔记列表
articles = []
if isinstance(data, list):
articles = data
elif isinstance(data, dict):
articles = data.get("data", data.get("list", data.get("articles", [])))
if isinstance(articles, dict):
articles = articles.get("list", articles.get("records", []))
if not articles:
return []
# 按互动数排序
def get_interaction_score(article):
# 优先从anaAdd对象获取互动数
ana_add = article.get("anaAdd", {})
interactive_count = ana_add.get("interactiveCount", 0) or article.get("interactiveCount", 0)
# 处理 "2w+" 这样的格式
if isinstance(interactive_count, str):
if 'w+' in interactive_count.lower():
num = float(interactive_count.lower().replace('w+', '').replace('w', ''))
return int(num * 10000)
try:
return int(interactive_count)
except:
pass
if interactive_count and int(interactive_count) > 0:
return int(interactive_count)
# 备用计算:点赞 + 收藏*2 + 评论*3 + 分享*5
like_count = parse_count(ana_add.get("useLikeCount", 0) or article.get("useLikeCount", 0))
collected_count = parse_count(ana_add.get("collectedCount", 0) or article.get("collectedCount", 0))
comment_count = parse_count(ana_add.get("useCommentCount", 0) or article.get("useCommentCount", 0))
share_count = parse_count(ana_add.get("useShareCount", 0) or article.get("useShareCount", 0))
return like_count + collected_count * 2 + comment_count * 3 + share_count * 5
sorted_articles = sorted(articles, key=get_interaction_score, reverse=True)
return sorted_articles[:top_n]
def parse_count(value) -> int:
"""解析计数值,支持 "2w+" 格式"""
if isinstance(value, int):
return value
if isinstance(value, str):
if 'w+' in value.lower():
num = float(value.lower().replace('w+', '').replace('w', ''))
return int(num * 10000)
try:
return int(value)
except:
return 0
return 0
def clean_text(text: str) -> str:
"""
清理文本中的特殊字符,用于表格单元格显示
清理内容:
- 空格
- 换行符(\r, \n)
- URL链接
- Image标记
- 特殊字符(<>{}[]|\)
"""
import re
if not text:
return ""
text = str(text)
# 移除URL
text = re.sub(r'https?://\S+', '', text)
# 移除Image标记
text = re.sub(r'Image:\s*\[.*?\]', '', text)
# 移除换行符
text = re.sub(r'[\r\n]+', '', text)
# 移除空格
text = text.replace(' ', '')
# 移除特殊字符
text = re.sub(r'[<>{}[\]\\|]', '', text)
return text.strip()
def generate_core_content(title: str, desc: str, user_name: str) -> str:
"""
生成笔记核心内容摘要
规则:主要讲述什么人做了什么事,内容丰富且信息完整
Args:
title: 笔记标题
desc: 笔记描述
user_name: 作者名称
Returns:
核心内容摘要(30-60字)
"""
import re
# 清理desc中的URL和特殊字符
desc_clean = re.sub(r'https?://\S+', '', desc) # 移除URL
desc_clean = re.sub(r'Image:\s*\[.*?\]', '', desc_clean) # 移除Image标记
desc_clean = re.sub(r'#\S+', '', desc_clean) # 移除话题标签
desc_clean = re.sub(r'[\r\n]+', '', desc_clean) # 移除换行符
desc_clean = re.sub(r'[<>{}[\]\\]', '', desc_clean) # 移除特殊字符
text = f"{title} {desc_clean}".strip()
# 识别主体(谁)
subject = user_name if user_name else "博主"
# 识别行为(做什么)
action = ""
topic = ""
# 旅行/风景类
if any(kw in text for kw in ["旅行", "旅游", "打卡", "景点", "出游", "攻略"]):
action = "分享"
location_match = re.search(r"在([^\s,,。!?]{2,8})(旅行|旅游|打卡|游玩)", text)
if location_match:
topic = f"{location_match.group(1)}旅行攻略与体验"
else:
topic = "旅行见闻与实用攻略"
# 美食类
elif any(kw in text for kw in ["美食", "做饭", "食谱", "餐厅", "探店", "好吃", "烹饪", "料理"]):
action = "推荐"
topic = "美食制作方法与餐厅探店体验"
# 穿搭/时尚类
elif any(kw in text for kw in ["穿搭", "穿衣", "服装", "时尚", "OOTD", "ootd", "搭配"]):
action = "展示"
topic = "时尚穿搭技巧与单品推荐"
# 美妆/护肤类
elif any(kw in text for kw in ["化妆", "妆容", "美妆", "护肤", "彩妆", "口红"]):
action = "分享"
topic = "美妆教程与护肤心得"
# 宠物类
elif any(kw in text for kw in ["宠物", "猫", "狗", "萌宠", "铲屎官"]):
action = "记录"
topic = "宠物日常与养护经验"
# 游戏类
elif any(kw in text for kw in ["游戏", "王者", "电竞", "玩家"]):
action = "分享"
topic = "游戏攻略与精彩操作"
# 搞笑/娱乐类
elif any(kw in text for kw in ["搞笑", "有趣", "沙雕", "表情包", "梗"]):
action = "创作"
topic = "趣味内容与搞笑段子"
# 生活/日常类
elif any(kw in text for kw in ["日常", "生活", "vlog", "记录", "Vlog", "VLOG"]):
action = "记录"
topic = "日常生活分享与个人见闻"
# 情感类
elif any(kw in text for kw in ["情感", "爱情", "恋爱", "故事", "感悟"]):
action = "分享"
topic = "情感故事与人生感悟"
# 教程/干货类
elif any(kw in text for kw in ["教程", "方法", "技巧", "攻略", "干货"]):
action = "传授"
topic = "实用技巧与干货教程"
# 默认
else:
action = "分享"
if title and len(title) > 5:
topic = title[:25] + "..."
else:
topic = "精彩内容与个人体验"
# 组合生成摘要
summary = f"{subject}{action}{topic}"
# 控制长度在30-60字
if len(summary) < 30:
if desc_clean and len(desc_clean) > 10:
extra = desc_clean[:30].strip()
summary = f"{summary},{extra}..."
elif len(summary) > 60:
summary = summary[:57] + "..."
# 最终清理:移除所有换行符和特殊字符
summary = re.sub(r'[\r\n]+', '', summary)
summary = re.sub(r'[<>{}[\]\\|]', '', summary)
return summary
def format_ranking_list(articles: list, category: str = "综合全部") -> str:
"""
将榜单数据格式化为表格样式
字段:排名、笔记信息、互动数、点赞、评论、收藏、分享
Args:
articles: 排序后的笔记列表
category: 当前分类
Returns:
表格格式的字符串
"""
if not articles:
return f"未获取到【{clean_text(category)}】分类的爆款内容数据"
output_lines = []
# 表头 - 加粗并添加图标
output_lines.append(f"**🔥 【{clean_text(category)}】七日爆款笔记**")
output_lines.append("| 排名 | 笔记信息 | 互动数 | 点赞 | 评论 | 收藏 | 分享 |")
output_lines.append("|:---:|:---|:---:|:---:|:---:|:---:|:---:|")
for idx, article in enumerate(articles, 1):
# 获取并清理所有字段
title = clean_text(article.get("title", "无标题")) or "无标题"
user_name = clean_text(article.get("userName", "未知用户")) or "未知用户"
photo_jump_url = article.get("photoJumpUrl", "#") or "#"
# URL中的空格编码为%20,其他特殊字符清理
photo_jump_url = photo_jump_url.replace(" ", "%20")
fans = clean_text(str(article.get("fans", "0"))) or "0"
# 从anaAdd对象获取互动数据并清理
ana_add = article.get("anaAdd", {})
interactive_count = clean_text(str(ana_add.get("interactiveCount", "0") or article.get("interactiveCount", "0"))) or "0"
add_interactive_count = clean_text(str(ana_add.get("addInteractiveount", "0") or article.get("addInteractiveount", "0"))) or "0"
like_count = clean_text(str(ana_add.get("useLikeCount", "0") or article.get("useLikeCount", "0"))) or "0"
add_like_count = clean_text(str(ana_add.get("addLikeCount", "0") or article.get("addLikeCount", "0"))) or "0"
comment_count = clean_text(str(ana_add.get("useCommentCount", "0") or article.get("useCommentCount", "0"))) or "0"
add_comment_count = clean_text(str(ana_add.get("addCommentCount", "0") or article.get("addCommentCount", "0"))) or "0"
collected_count = clean_text(str(ana_add.get("collectedCount", "0") or article.get("collectedCount", "0"))) or "0"
add_collected_count = clean_text(str(ana_add.get("addCollectedCunt", "0") or article.get("addCollectedCunt", "0"))) or "0"
share_count = clean_text(str(ana_add.get("useShareCount", "0") or article.get("useShareCount", "0"))) or "0"
add_share_count = clean_text(str(ana_add.get("addShareCount", "0") or article.get("addShareCount", "0"))) or "0"
# 排名(前三名带奖牌)
if idx == 1:
rank_display = "🥇"
elif idx == 2:
rank_display = "🥈"
elif idx == 3:
rank_display = "🥉"
else:
rank_display = str(idx)
# 笔记信息:标题链接 + 作者(粉丝数)
if photo_jump_url and photo_jump_url != "#":
note_info = f"[{title}]({photo_jump_url})<br>{user_name}({fans}粉丝)"
else:
note_info = f"{title}<br>{user_name}({fans}粉丝)"
# 格式化数字
def format_num(val):
try:
num = parse_count(val)
if num >= 10000:
return f"{num // 10000}w+"
return str(val)
except:
return str(val)
# 格式化显示:累计数值<br>↑新增数值
interactive_display = f"{format_num(interactive_count)}<br>↑新增{format_num(add_interactive_count)}"
like_display = f"{format_num(like_count)}<br>↑新增{format_num(add_like_count)}"
comment_display = f"{format_num(comment_count)}<br>↑新增{format_num(add_comment_count)}"
collect_display = f"{format_num(collected_count)}<br>↑新增{format_num(add_collected_count)}"
share_display = f"{format_num(share_count)}<br>↑新增{format_num(add_share_count)}"
output_lines.append(f"| {rank_display} | {note_info} | {interactive_display} | {like_display} | {comment_display} | {collect_display} | {share_display} |")
return "\n".join(output_lines)
def analyze_content(article: dict) -> str:
"""
基于笔记的具体文本内容,生成专业且通俗的内容分析
分析规则:
1. 内容概述:简明扼要地概括笔记核心内容
2. 热点利用:分析笔记借用了哪些热点话题或趋势
3. 传播作用:阐述内容起到的作用
4. 达成效果:说明内容达到的效果
Args:
article: 笔记数据
Returns:
内容分析字符串(专业通俗风格)
"""
# 提取文本内容
title = article.get("title", "")
desc = article.get("desc", "")
# 合并所有文本用于分析
all_text = f"{title} {desc}"
# 动态提取关键信息
content_analysis = []
# 1. 内容概述 - 基于实际内容动态生成
topic_keywords = []
if "旅行" in all_text or "风景" in all_text or "自由" in all_text:
topic_keywords.append("旅行生活")
if "猫" in all_text or "狗" in all_text or "宠物" in all_text:
topic_keywords.append("萌宠日常")
if "游戏" in all_text or "王者" in all_text:
topic_keywords.append("游戏娱乐")
if "手工" in all_text or "DIY" in all_text:
topic_keywords.append("手工创意")
if "美食" in all_text or "做饭" in all_text:
topic_keywords.append("美食分享")
if "穿搭" in all_text or "时尚" in all_text:
topic_keywords.append("时尚穿搭")
if "上学" in all_text or "学校" in all_text:
topic_keywords.append("校园生活")
if "表情包" in all_text or "梗图" in all_text:
topic_keywords.append("趣味内容")
if "帅哥" in all_text or "美女" in all_text:
topic_keywords.append("颜值分享")
# 从desc中提取标签
if "#" in desc:
tags = [t.strip() for t in desc.split("#") if t.strip()]
if tags:
topic_keywords.extend(tags[:2])
# 动态生成内容概述
if topic_keywords:
topic_str = "、".join(topic_keywords[:3])
content_analysis.append(f"本笔记围绕{topic_str}等话题展开")
else:
if len(title) > 0:
key_part = title[:20] if len(title) > 20 else title
content_analysis.append(f"本笔记聚焦{key_part}等话题")
# 2. 热点利用 - 基于实际内容动态判断
hotspot_detected = []
if any(word in all_text for word in ["热门", "爆火", "流行"]):
hotspot_detected.append(("热门话题", "流量热点"))
if any(word in all_text for word in ["治愈", "温暖", "感动"]):
hotspot_detected.append(("治愈系", "情感热点"))
if any(word in all_text for word in ["搞笑", "有趣", "沙雕"]):
hotspot_detected.append(("搞笑内容", "娱乐热点"))
if any(word in all_text for word in ["日常", "生活", "vlog"]):
hotspot_detected.append(("生活分享", "日常热点"))
if hotspot_detected:
hotspots = [h[0] for h in hotspot_detected[:2]]
content_analysis.append(f"笔记借力{'与'.join(hotspots)}等话题吸引关注")
else:
content_analysis.append("笔记紧扣用户感兴趣的话题")
# 3. 传播作用
if any(word in all_text for word in ["分享", "推荐", "安利"]):
content_analysis.append("通过分享体验满足用户好奇心")
elif any(word in all_text for word in ["教程", "攻略", "方法"]):
content_analysis.append("通过提供实用价值满足用户需求")
else:
content_analysis.append("满足用户对相关内容的需求")
# 4. 达成效果
ana_add = article.get("anaAdd", {})
like_count = parse_count(ana_add.get("useLikeCount", 0) or article.get("useLikeCount", 0))
collected_count = parse_count(ana_add.get("collectedCount", 0) or article.get("collectedCount", 0))
if like_count > 10000 or collected_count > 1000:
content_analysis.append("获得高互动传播效果")
else:
content_analysis.append("获得良好传播效果")
# 组合分析内容
analysis = ",".join(content_analysis) + "。"
return analysis
def main():
parser = argparse.ArgumentParser(description="获取小红书七日爆款笔记")
parser.add_argument("--rank_date", required=False, default=None, help="查询日期(格式:yyyy-MM-dd,默认今天)")
parser.add_argument("--category", required=False, default=None, help="分类名称(如:时尚穿搭、美食佳肴等),不传则根据关键词匹配")
parser.add_argument("--keyword", required=False, default=None, help="用户输入的关键词,用于自动匹配分类")
parser.add_argument("--top_n", type=int, default=10, help="返回前N条数据(默认10)")
parser.add_argument("--save_json", type=str, default=None, help="将原始API数据保存到指定JSON文件路径")
parser.add_argument("--list_categories", action="store_true", help="列出所有可用分类")
args = parser.parse_args()
# 列出所有分类
if args.list_categories:
print("可用分类列表:")
for cat in get_all_categories():
print(f" - {cat}")
return 0
try:
# 处理日期参数
rank_date, is_auto = get_query_date(args.rank_date)
# 处理分类参数
if args.category:
category = args.category
elif args.keyword:
category = match_category(args.keyword)
print(f"根据关键词【{args.keyword}】匹配到分类:【{category}】")
else:
category = "综合全部"
print(f"正在获取小红书七日爆款笔记数据...")
print(f"当前时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
if is_auto:
cutoff_time = datetime.now().replace(hour=19, minute=0, second=0, microsecond=0)
if datetime.now() >= cutoff_time:
print(f"当前已过19:00,查询昨日数据(当日已更新)")
else:
print(f"当前未过19:00,查询前天数据(等待当日19:00更新)")
print(f"查询日期: {rank_date}")
print(f"分类: {category}")
print("-" * 60)
# 获取数据
data = fetch_explosive_articles(rank_date, category)
# 自动保存原始API数据到临时文件(供后续HTML生成复用,避免重复请求)
# 如果指定了 --save_json,使用指定路径;否则自动保存到临时目录
if args.save_json:
save_path = args.save_json
else:
temp_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", ".cache")
os.makedirs(temp_dir, exist_ok=True)
safe_category = "".join(c for c in category if c.isalnum() or c in ('_', '-'))
save_path = os.path.join(temp_dir, f"xhs_weekly_{safe_category}_{rank_date}.json")
os.makedirs(os.path.dirname(save_path) or ".", exist_ok=True)
with open(save_path, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"原始数据已保存到: {save_path}")
# 处理并排序
articles = process_ranking_data(data, args.top_n)
# 检查数据量是否足够
if len(articles) < 10:
print(f"提示:当前获取到 {len(articles)} 条数据,不足10条")
print("建议:可尝试查询其他日期或其他分类的数据")
print("-" * 60)
# 格式化输出
ranking_list = format_ranking_list(articles, category)
print(ranking_list)
# 返回统计信息
print("\n" + "=" * 60)
if articles:
print(f"共获取到 {len(articles)} 条【{category}】爆款内容数据")
else:
print(f"未获取到【{category}】分类的爆款内容数据")
print("建议:尝试查询其他日期或其他分类的数据")
return 0
except Exception as e:
print(f"错误: {str(e)}", file=sys.stderr)
return 1
if __name__ == "__main__":
sys.exit(main())