
Wechat 10w Hot
- 303 installs
- 316 repo stars
- Updated August 4, 2026
- redfox-data/redfox-community
Pushes WeChat articles that reached 100k+ reads, collecting 1000+ viral pieces daily across categories with four-dimension analysis and HTML report export.
About
A viral-article recommender that surfaces WeChat posts hitting 100k+ reads across 23 categories with pattern analysis. A content creator uses it to find proven viral content, study what works, and export styled HTML reports.
- Daily collection of 1000+ 100k-read articles across 23 categories
- Four-dimension content analysis and WeChat-style HTML/PDF reports
Wechat 10w Hot by the numbers
- 303 all-time installs (skills.sh)
- +22 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #863 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 wechat-10w-hotAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 303 |
|---|---|
| repo stars | ★ 316 |
| Last updated | August 4, 2026 |
| Repository | redfox-data/redfox-community ↗ |
What it does
Pushes WeChat articles that reached 100k+ reads, collecting 1000+ viral pieces daily across categories with four-dimension analysis and HTML report export.
Files
公众号10w+文章
1. 简介
一句话定位:公众号10w+阅读爆文推荐工具,全网持续收录每日1000+条公众号10w+文章,支持按领域分类查询、智能爆款规律分析和HTML报告导出。
核心价值:
- 海量收录:每日收录1000+条10w+阅读文章,覆盖23个标准分类
- 智能分析:基于四维度内容分析(内容概述、热点利用、传播作用、达成效果)
- 可视化报告:自动生成公众号风格HTML页面,支持PDF导出
适用对象:公众号运营者、内容创作者、自媒体编辑、市场运营、爆文研究者。
2. 功能特性
核心功能
| 功能模块 | 能力描述 | 核心价值 |
|---|---|---|
| 📊 爆文榜单推送 | 获取全领域10w+阅读文章TOP50 | 快速了解公众号爆文风向 |
| 🏷️ 领域分类查询 | 23个标准分类独立查询 | 精准定位垂直领域爆文 |
| 📝 四维度内容分析 | 内容概述/热点利用/传播作用/达成效果 | 深度解析爆文成功要素 |
| 📈 爆款规律分析 | 标题特征/内容主题/发布时间/账号特征 | 提炼可复用的爆款方法论 |
| 🎨 HTML可视化报告 | 微信绿主题设计,支持PDF导出 | 便于分享存档和数据汇报 |
| ⏰ 订阅推送 | 每日19:30定时推送 | 持续追踪,不错过爆文 |
特色亮点
- 智能时间判断:根据数据更新时间(18:30)自动计算正确查询区间
- 分页预览机制:首次展示前10条,按需展示完整50条
- 四维度分析:每篇文章从内容概述、热点利用、传播作用、达成效果四方面深度分析
- HTML防分页:PDF导出自适应单页模式,所有内容完整展示
3. 一键安装
鉴权
获取 API Key
请前往 红狐hub 获取API KEY
配置 API Key
方案1: 以OpenClaw为例,将REDFOX_API_KEY添加到~/.openclaw/openclaw.json中,部分内容如下:
{ "env": { "REDFOX_API_KEY": "ak_xxxx..." } }方案2: 终端配置:
export REDFOX_API_KEY="ak_xxxx..."依赖安装
无需额外安装,脚本使用Python标准库(urllib.request)。
环境变量配置
| 变量名 | 说明 | 必填 |
|---|---|---|
REDFOX_API_KEY | 红狐 API Key | 是 |
4. 使用指南
基础使用
查询全领域10w+文章(总榜)
启动后提示用户:「技能已加载完成。是否为您推送最新的10w+阅读文章。」
总榜请求直接推送最新10w+阅读文章TOP50(首次预览展示前10条)。
领域关键词查询
输入具体领域关键词(如"AI编程"、"财经"、"健康饮食"),系统自动匹配23个标准分类并输出该领域TOP10。
标准23分类:人文资讯、知识百科、健康养生、时尚潮流、美食餐饮、乐活生活、旅游出行、搞笑幽默、情感心理、体育娱乐、美容美体、文摘精选、民生资讯、财富理财、科技数码、创投商业、汽车交通、房产楼市、职场发展、教育考试、学术研究、企业品牌、总排名。
分类泛化映射规则详见 references/category-mapping.md。
高级使用
标准执行流程
1. 用户意图识别:智能体识别总榜请求/领域查询/模糊输入 2. 获取爆文数据:调用 scripts/fetch_hot_articles.py 脚本(必须调用,禁止自行生成) 3. 爆款规律分析:基于实际文章数据进行四维度分析 4. 询问订阅:主动询问用户是否需要订阅特定领域 5. 生成HTML页面:调用 scripts/generate_hot_html.py 生成可视化报告 6. 处理用户订阅选择:根据用户回复执行订阅逻辑
脚本参数说明
python scripts/fetch_hot_articles.py --type "分类名称" --start_date YYYY-MM-DD --end_date YYYY-MM-DD --mode preview --limit 10 --source "公众号10w+阅读文章推荐"| 参数 | 说明 | 示例 |
|---|---|---|
--type | 标准分类名称,默认"总排名" | --type "科技数码" |
--start_date | 开始日期(必传),YYYY-MM-DD | --start_date 2026-05-13 |
--end_date | 结束日期(必传),YYYY-MM-DD | --end_date 2026-05-14 |
--source | 数据源(固定值) | --source "公众号10w+阅读文章推荐" |
--mode | 输出模式:preview(前10条) / full(全部) | --mode preview |
--limit | 预览模式下显示数量 | --limit 10 |
--temp_file | 临时数据文件路径 | --temp_file temp_articles.json |
时间参数计算规则(重要)
数据更新时间:每天 18:30 同步前一日数据。
时间判断逻辑:智能体必须根据当前时间自动计算正确的查询日期。
| 当前时间 | 用户询问 | 实际查询区间 | 原因 |
|---|---|---|---|
| < 18:30 | 今日文章 | T-2 ~ T-1 | 昨天数据未更新,查前天区间 |
| >= 18:30 | 今日文章 | T-1 ~ T | 昨天数据已更新,查昨天区间 |
| < 18:30 | 昨天文章 | T-2 ~ T-1 | 昨天数据未更新,查前天区间 |
| >= 18:30 | 昨天文章 | T-1 ~ T | 昨天数据已更新 |
默认时间规则:用户提到"最近"、"最新"等无明确时间说法时,默认查询过去7天。
订阅推送时间参数:订阅推送(每天19:30)查询昨天(T-1)的数据。
典型场景示例(假设今天是2026-05-14):
| 用户询问 | 当前时间 | 实际查询区间 | 原因 |
|---|---|---|---|
| 今日文章 | 11:19 | start_date=2026-05-12, end_date=2026-05-13 | 昨天数据未更新,查前天区间 |
| 今日文章 | 19:30 | start_date=2026-05-13, end_date=2026-05-14 | 昨天数据已更新,查昨天区间 |
| 昨天文章 | 11:19 | start_date=2026-05-12, end_date=2026-05-13 | 昨天数据未更新,但前天数据已更新 |
| 昨天文章 | 19:30 | start_date=2026-05-13, end_date=2026-05-14 | 昨天数据已更新 |
时间不一致提示规则
只要用户询问的时间和实际查询的时间不一致,就需要提示:
- 用户询问"今天的数据",实际查询昨天:「非常抱歉🙏,今天的数据要明天才会更新,我将为您查询昨天的xx月xx日10W+文章。」
- 用户询问"昨天数据",实际查询前天:「非常抱歉🙏,昨天的数据还未更新,我将为您查询前天的xx月xx日10W+文章。」
- 用户询问时间早于回溯日期:「非常抱歉🙏,目前最多支持回溯过去30天,我将为您查询最接近您需求的时间范围~」
分页展示策略
- 首次展示:
--mode preview --limit 10,展示前10条 - 用户要求拓展:
--mode full,展示所有数据 - 数据不超过10条:直接展示所有,无需询问
- 超过10条时底部提示:"还有X条数据未展示,是否需要全部展示?"
文章数量较少提示规则
当某赛道某日10w+文章少于10篇时,提示:「💡 xx日xx赛道10w+文章较少,您可以拓展过去30天或者看看综合10w+文章~」
输出格式
脚本输出按以下顺序:数据说明 → 文章概览表格 → 文章详情 → 统计信息。
文章概览表格:
| 序号 | 标题 | 作者 | 阅读数 |
|------|------|------|--------|
| 1 | [标题](文章链接) | [作者名称](公众号名片链接) | 5w+ |文章详情格式:
**序号、[标题](文章链接)**
📄 作者:[作者名称](公众号名片链接)
👀 阅读数:阅读数
⏰ 发布时间:发布时间
🔍 内容分析:基于四维度规则的分析内容
---四维度内容分析规则
每篇文章必须从以下四个维度进行分析:
- 内容概述:简明扼要地概括文章核心内容
- 热点利用:分析文章借用了哪些热点话题或趋势
- 传播作用:阐述内容起到的作用(满足用户需求、引发情感共鸣、提供实用价值)
- 达成效果:说明内容达到的效果(提升品牌认知、完成用户转化、促进信息传播)
爆款规律分析
在完整展示榜单数据后执行,基于实际文章数据进行四方面分析:
- 标题特征:总结标题共性和亮点
- 内容主题:分析话题类型、传播价值
- 发布时间:分析发布时段规律
- 公众号特征:分析账号类型和内容定位特点
HTML页面生成
python scripts/generate_hot_html.py --temp_file temp_articles.json --output "热门文章_榜单.html" --display_count 10| 参数 | 说明 |
|---|---|
--temp_file | 临时JSON文件路径(默认:temp_articles.json) |
--output | 输出文件路径 |
--display_count | 展示的文章数量,必须与对话中展示的数量一致 |
HTML视觉规范:
- 主色:
rgb(0, 179, 84)(微信绿) - 辅助色:
#0088ff(阅读数、用户名称) - 序号1-3使用🥇🥈🥉,4往后使用数字
- 用户名称可点击跳转公众号名片(
https://open.weixin.qq.com/qr/code?username={accountId}) - PDF导出:自适应单页模式,
pagebreak: { mode: 'none' }
订阅服务
规律分析后主动询问用户是否需要订阅:
📬 订阅服务
是否需要订阅具体赛道的账号表现?我们支持:
人文资讯、知识百科、健康养生、时尚潮流、美食餐饮、乐活生活、旅游出行、搞笑幽默、情感心理、体育娱乐、美容美体、文摘精选、民生资讯、财富理财、科技数码、创投商业、汽车交通、房产楼市、职场发展、教育考试、学术研究、企业品牌、总排名
订阅推送 - 每天19点30分推送最新10w+公众号爆文
暂不需要 - 仅本次查询命令速查表
| 场景 | 命令示例 |
|---|---|
| 总榜预览 | python scripts/fetch_hot_articles.py --type "总排名" --start_date 2026-05-12 --end_date 2026-05-13 --mode preview --limit 10 |
| 总榜完整 | python scripts/fetch_hot_articles.py --type "总排名" --start_date 2026-05-12 --end_date 2026-05-13 --mode full |
| 领域查询 | python scripts/fetch_hot_articles.py --type "科技数码" --start_date 2026-05-13 --end_date 2026-05-14 --mode preview --limit 10 |
| 生成HTML | python scripts/generate_hot_html.py --temp_file temp_articles.json --output "榜单.html" --display_count 10 |
5. 使用场景
场景一:公众号运营者获取写作灵感
角色:公众号编辑/运营 需求:每天早晨查看前一天10w+爆文,提取爆款选题和标题套路 使用方式:输入"今日爆文",获取全领域TOP50 + 爆款规律分析 预期收益:快速掌握当日爆文风向,获得可复用的标题和选题方法论
场景二:垂直领域内容深耕
角色:垂直领域内容创作者(如健康养生、科技数码) 需求:持续追踪本领域爆文,了解同行内容策略 使用方式:查询特定领域TOP50,分析爆款规律,订阅每日推送 预期收益:精准对标同领域头部内容,提升自身内容竞争力
场景三:品牌营销内容策划
角色:品牌营销策划 需求:研究公众号爆文传播规律,为品牌内容制作提供参考 使用方式:跨领域查询爆文榜单,分析标题特征和传播作用 预期收益:掌握公众号内容传播密码,制定高效的品牌内容策略
场景四:自媒体创业方向调研
角色:自媒体创业者 需求:了解各领域公众号的流量分布和爆文特征,选择适合的切入方向 使用方式:连续查询多个领域近7天数据,对比各领域爆文数量和质量 预期收益:基于数据做出领域选择决策,从起号阶段就走在正确方向
6. 项目架构
目录结构
wechat-10w-hot/
├── SKILL.md # 技能描述文件
├── scripts/
│ ├── fetch_hot_articles.py # 爆文数据获取脚本
│ └── generate_hot_html.py # HTML页面生成脚本
└── references/
├── api-spec.md # API接口规范
└── category-mapping.md # 分类泛化映射规则技术栈
| 组件 | 技术 | 说明 |
|---|---|---|
| 脚本语言 | Python 3 | 使用标准库(urllib.request) |
| 数据接口 | Redfox API (GET) | https://redfox.hk/story/api/cozeSkill/getWxDataByCategoryAndTime |
| 认证方式 | X-API-KEY | 请求头认证 |
| 报告模板 | HTML/CSS/JS | 微信绿主题风格 |
| PDF导出 | html2pdf.js | 自适应单页模式 |
核心模块说明
| 模块 | 功能 |
|---|---|
fetch_hot_articles.py | 根据分类和时间获取10w+热门文章数据,生成摘要表格和详情列表,保存到临时JSON文件 |
generate_hot_html.py | 从临时JSON文件读取数据,生成公众号风格HTML页面,支持PDF导出 |
api-spec.md | API接口规范参考 |
category-mapping.md | 分类泛化映射规则参考 |
资源索引
- 脚本: 见 scripts/fetch_hot_articles.py(用途: 根据分类和时间获取10w+热门文章数据)
- 脚本: 见 scripts/generate_hot_html.py(用途: 从临时JSON文件读取数据,生成公众号风格HTML页面)
- 参考: 见 references/api-spec.md(何时读取: 查看API接口规范时使用)
- 参考: 见 references/category-mapping.md(何时读取: 查看分类泛化映射规则时使用)
7. 常见问答
安装相关
Q: 脚本运行报错 "REDFOX_API_KEY not found" A: 请确保已配置环境变量 REDFOX_API_KEY,可参考上方鉴权章节配置。
Q: 是否需要安装Python依赖? A: 不需要,脚本使用Python标准库(urllib.request),无需额外安装。
使用相关
Q: 为什么查询"今天"的文章返回的是昨天的? A: 数据每日18:30同步前一日数据。如果在18:30之后查询,可获取昨日数据;18:30之前查询需使用前日数据。系统会自动计算并提示。
Q: 如何查看完整的50条数据? A: 首次预览展示前10条后,回复「全部展示」或「是」,系统会使用 --mode full 展示所有50条。
Q: 用户输入的领域关键词如何匹配? A: 系统通过分类泛化映射规则自动匹配,如"AI" → "科技数码","减肥" → "健康养生"。详见 references/category-mapping.md。
Q: HTML中的文章数量和对话中不一致? A: 使用 --display_count 参数控制HTML展示数量,必须与对话中实际展示的数量一致。
故障排除
Q: 查询返回空数据? A: 可能原因:1) 该领域在查询时间段内无10w+文章;2) API Key 无效或过期。系统会提示推荐查看综合榜单或其他分类。
Q: PDF导出出现分页? A: HTML生成时已配置 pagebreak: { mode: 'none' } 和 page-break-inside: avoid,如果仍有分页请检查html2pdf.js配置。
Q: 脚本输出被截断? A: 确保使用 preview 模式首次展示,仅输出10条避免截断。用户需要时再使用 full 模式展示全部。
WeChat 10W+ Article Recommendations
---
Introduction
Quickly find WeChat Official Account articles that reached 10w+ reads in a single day, and stay on top of top-traffic trends and topic direction.
Core Value
- Capture viral articles at a glance: Daily indexing of 10w+ read articles across industries — instantly see where top traffic is heading
- Lock in vertical niches: Query and subscribe to 10w+ updates across 22 track categories so your topics stay on course
- Decode viral DNA: Automatically break down title traits, content themes, posting timing, and account characteristics into reusable creative patterns
- Immersive viewing and export: WeChat-green themed visual ranking pages with one-click PDF export for team sharing and offline review
Who It's For
- 📝 WeChat editors / operators — Track trends, titles, and account mix
- 📊 Content leads — Need shareable, printable ranking pages
- 📈 Growth / business teams — Monitor competitors and niche 10w+ viral content by track
---
Core Capabilities
- 10w+ article recommendations: Daily update of yesterday's latest WeChat Official Account 10w+ read article rankings
- Overall + niche rankings: Browse all-category hot articles or focus on tech, finance, health, and 22 other verticals
- Viral pattern analysis: More than a data list — extract title, content, timing, and account patterns from real viral posts
- Visual ranking page: Generate visual HTML layouts with image or PDF export
- Subscription push: Subscribe by niche for daily scheduled pushes of the latest 10w+ articles (when the platform supports it)
---
API Key Acquisition & Security
- This skill requires the environment variable:
REDFOX_API_KEY. REDFOX_API_KEYis provided by RedFoxHub (https://redfox.hk).- Register at RedFoxHub to obtain your
REDFOX_API_KEY. - Configure
REDFOX_API_KEYas a device environment variable before using this skill. - Before providing your key, confirm its source, available scope, validity period, and whether reset/revocation is supported.
- Do not hard-code or expose the key in plaintext in code, prompts, logs, or output files.
---
Usage Guide
Describe what you need in plain language — no fixed commands to memorize.
Quick phrase reference
| Intent | Example phrase | What you get |
|---|---|---|
| Latest 10w+ viral articles | "What are the latest 10w+ viral articles?" | Overall ranking for the latest available date |
| Niche track query | "What 10w+ tech articles were hot this past week?" | Ranking for that category and time window |
| View all data | "Expand all — show me 50 entries" | Full 50 entries within the same time range |
| Visual share and export | "Generate a ranking page I can export to PDF" | Visual page on top of the ranking, with export support |
| Subscribe | "Subscribe me to daily finance 10w+ articles" | Scheduled push of 10w+ articles after subscription |
Sample output
💡 Data note
10w+ read viral article recommendations update daily at 19:30 with yesterday's article data.
📊 Article overview
| # | Title | Author | Reads |
|---|---|---|---|
| 🥇 1 | Must-read for workplace newcomers: 5 tips to fit in fast | Workplace Growth | 10w+ |
| 🥈 2 | Workplace communication: 3 sentences you must never say! | Workplace Tips | 10w+ |
| 3 | … | … | … |
📝 Article details
1、[Must-read for workplace newcomers: 5 tips to fit in fast](https://mp.weixin.qq.com/s/xxx)
📄 Author: Workplace Growth 👀 Reads: 10w+ ⏰ Published: 2026-05-15
🔍 Content analysis: Summary… | Trend leverage… | Spread role… | Outcome…
---
📊 Viral pattern analysis
Title traits: … Content themes: … Posting timing: … Account characteristics: …
---
📬 Subscription
Subscribe to a specific niche? We support subscriptions across 22 track categories.
1️⃣ Subscribe — Daily push of latest 10w+ WeChat articles at 19:30 2️⃣ Not now — This query only
---
Use Cases
| Scenario | Role | Example question | Benefit |
|---|---|---|---|
| Daily trend tracking | WeChat operator | "Today's viral articles / latest 10w+ articles" | Quickly grasp top traffic and topic direction |
| Competitor niche watch | Content lead | "What's hot in finance 10w+ lately?" | Lock in vertical niches and keep topics on track |
| Team review | Editor lead | "Export a printable viral article ranking" | Easier offline breakdown and meeting collaboration |
| Pattern learning | Junior editor | "What do these viral articles have in common?" | From casual reading to reusable creative models |
---
Important data notes
Update schedule and lookback
| Ranking type | Update time | Lookback |
|---|---|---|
| Overall | Daily 19:30 — previous day's data | Past 30 days |
| Niche tracks | Daily 19:30 — previous day's data | Past 30 days |
Supported niches (22)
Humanities & news, knowledge encyclopedia, health & wellness, fashion, food & dining, lifestyle, travel, humor, emotions & psychology, sports & entertainment, beauty, digest picks, civic news, wealth & finance, tech & digital, venture & business, automotive, real estate, career development, education & exams, academic research, corporate brands
Data freshness
Data is not real-time. Engagement figures reflect the collection moment and may differ from live platform data.
---
公众号 10w+文章 / wechat-10w-hot
---
简介
帮你快速找到公众号平台阅读数当日达到 10w+ 的爆款文章,掌握全网头部流量与选题方向。
核心价值
- 全网爆文一键捕获:每日收录全网各行业 10w+ 阅读量热门文章,瞬间掌握头部流量走向
- 垂直领域精准锁定:支持按 22 个赛道分类查询与订阅特定领域 10w+ 资讯,确保选题不偏航
- 爆款基因深度解码:自动拆解爆文的标题特征、内容主题、发布时段与公众号特征,提炼可复用的创作规律
- 沉浸式阅览与导出:生成微信绿主题的可视化榜单页,支持一键导出 PDF,方便团队分享与离线复盘
适用对象
- 📝 公众号编辑 / 运营 — 追热点、看标题与账号分布
- 📊 内容负责人 — 需要可分享、可打印的榜单页
- 📈 增长 / 商务 — 按赛道盯竞品与行业 10w+ 爆文动向
---
核心功能
- 10w+文章推荐:每日更新昨日最新的公众号 10w+ 阅读文章榜单
- 总榜 + 分赛道:既可看全品类热门,也可锁定科技、财经、健康等 22 个垂直领域
- 爆款规律分析:不只给数据列表,还从真实爆文中提炼标题、内容、时段、账号维度的创作规律
- 可视化榜单页:生成带可视化布局的 HTML 文件,支持导出图片或 PDF
- 订阅推送:支持按赛道订阅每日定时推送最新 10w+ 文章(需平台支持)
---
密钥获取与安全说明
- 本技能需要使用环境变量:
REDFOX_API_KEY。 REDFOX_API_KEY由 红狐 hub (https://redfox.hk)提供。- 请前往 红狐 hub 注册账号,获取
REDFOX_API_KEY。 - 配置设备环境变量
REDFOX_API_KEY后使用本技能。 - 在提供密钥前,请先确认密钥来源、可用范围、有效期及是否支持重置/撤销。
- 禁止在代码、提示词、日志或输出文件中硬编码/明文暴露密钥。
---
使用指南
直接用自然语言说出你的需求即可,无需记忆固定命令。
常用说法速查
| 意图 | 示例话术 | 效果 |
|---|---|---|
| 看最新 10w+爆文 | "最新的 10w+ 爆文有哪些?" | 输出最新可用日期的总榜榜单 |
| 查垂直赛道 | "科技类最近一周有哪些 10w+ 热门?" | 按分类与时间窗口输出对应赛道榜单 |
| 查看全部数据 | "展开全部,给我看 50 条" | 在同时间范围内展示完整的 50 条 |
| 可视化分享与导出 | "生成可以导出 PDF 的榜单页" | 在榜单基础上生成可视化页面,支持导出 |
| 订阅推送 | "帮我订阅财经赛道的每日 10w+文章" | 订阅后按照时间主动推送 10w+文章 |
输出示例
💡 数据说明
10w+阅读爆文推荐将在每日 19 点 30 分准时更新昨日文章数据。
📊 文章概览
| 序号 | 标题 | 作者 | 阅读数 |
|---|---|---|---|
| 🥇 1 | 职场新人必看:5 个让你快速融入团队的技巧 | 职场成长社 | 10w+ |
| 🥈 2 | 职场沟通:这 3 句话千万别说! | 职场干货铺 | 10w+ |
| 3 | … | … | … |
📝 文章详情
1、[职场新人必看:5 个让你快速融入团队的技巧](https://mp.weixin.qq.com/s/xxx)
📄 作者:职场成长社 👀 阅读数:10w+ ⏰ 发布时间:2026-05-15
🔍 内容分析:内容概述… | 热点利用… | 传播作用… | 达成效果…
---
📊 爆款规律分析
标题特征:… 内容主题:… 发布时间:… 公众号特征:…
---
📬 订阅服务
是否需要订阅具体赛道的账号表现?我们支持 22 个赛道分类订阅。
1️⃣ 订阅推送 — 每天 19 点 30 分推送最新 10w+公众号爆文 2️⃣ 暂不需要 — 仅本次查询
---
使用场景
| 场景 | 角色 | 示例问法 | 收益 |
|---|---|---|---|
| 追每日热点 | 公众号运营 | "今日爆文 / 最新 10w+ 文章" | 快速掌握头部流量与选题方向 |
| 盯竞品赛道 | 内容负责人 | "财经类 10w+ 最近有什么热门" | 垂直领域精准锁定,选题不偏航 |
| 团队复盘 | 编辑主管 | "导出一份可打印的爆文榜单" | 离线拆解、会议共创更方便 |
| 规律学习 | 新人编辑 | "分析一下这些爆文有什么共同点" | 从感性阅读到可复用的创作模型 |
---
重要数据说明
更新时间与数据回溯
| 榜单类型 | 更新时间 | 可回溯范围 |
|---|---|---|
| 全站总榜 | 每日 19:30 同步前一日数据 | 过去 30 天 |
| 分赛道榜 | 每日 19:30 同步前一日数据 | 过去 30 天 |
支持赛道(22 个)
人文资讯、知识百科、健康养生、时尚潮流、美食餐饮、乐活生活、旅游出行、搞笑幽默、情感心理、体育娱乐、美容美体、文摘精选、民生资讯、财富理财、科技数码、创投商业、汽车交通、房产楼市、职场发展、教育考试、学术研究、企业品牌
数据时效
数据非实时更新,文章互动数据为采集时刻的真实数据,与实时数据存在差异
---
API接口规范
接口信息
- 接口地址:
https://redfox.hk/story/api/cozeSkill/getWxDataByCategoryAndTime - 请求方法:GET
- Content-Type:application/json
认证方式
| 参数 | 说明 |
|---|---|
| X-API-KEY | API密钥,从环境变量 REDFOX_API_KEY 获取,未设置则自动从 shell 配置文件(~/.zshrc、~/.bash_profile 等)读取 |
请求头
Content-Type: application/json
X-API-KEY: <your_api_key>请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| type | string | 是 | 分类名称(标准23分类之一) |
| source | string | 是 | 数据来源,固定值:"公众号10w+阅读文章推荐" |
| startDate | string | 是 | 开始日期,格式:YYYY-MM-DD |
| endDate | string | 是 | 结束日期,格式:YYYY-MM-DD |
标准分类列表
共23个标准分类:
- 人文资讯、知识百科、健康养生、时尚潮流、美食餐饮、乐活生活
- 旅游出行、搞笑幽默、情感心理、体育娱乐、美容美体、文摘精选
- 民生资讯、财富理财、科技数码、创投商业、汽车交通、房产楼市
- 职场发展、教育考试、学术研究、企业品牌、总排名
请求示例
1. 查询总排名(昨日数据)
GET https://redfox.hk/story/api/cozeSkill/getWxDataByCategoryAndTime?type=总排名&source=公众号10w+阅读文章推荐&startDate=2026-05-13&endDate=2026-05-142. 查询科技数码分类
GET https://redfox.hk/story/api/cozeSkill/getWxDataByCategoryAndTime?type=科技数码&source=公众号10w+阅读文章推荐&startDate=2026-05-13&endDate=2026-05-143. 查询财富理财分类
GET https://redfox.hk/story/api/cozeSkill/getWxDataByCategoryAndTime?type=财富理财&source=公众号10w+阅读文章推荐&startDate=2026-05-10&endDate=2026-05-14响应数据结构
{
"code": 200,
"message": "success",
"data": {
"tenWReadingRank": [
{
"accountId": "zepinghongguan",
"clicksCount": "10w+",
"commentCount": "3",
"content": "文章内容摘要...",
"coverUrl": "https://...",
"fans": "100w+",
"interactiveCount": "3413",
"likeCount": "606",
"orderNum": 0,
"oriUrl": "https://mp.weixin.qq.com/s?...",
"originalFlag": 1,
"photoId": "...",
"publicTime": "2026-04-15 00:01:14",
"shareCount": "2613",
"summary": "摘要内容",
"thumbnail": "https://...",
"title": "文章标题",
"type": "财富",
"userHeadUrl": "https://...",
"userName": "作者名称",
"watchCount": "191"
}
]
}
}数据字段说明
| 字段名 | 说明 |
|---|---|
| accountId | 公众号ID |
| clicksCount | 阅读数(如:10w+、5w+) |
| commentCount | 评论数 |
| content | 文章内容摘要 |
| coverUrl | 封面图URL |
| fans | 粉丝数 |
| interactiveCount | 互动数 |
| likeCount | 点赞数 |
| oriUrl | 文章原文链接 |
| publicTime | 发布时间 |
| shareCount | 分享数 |
| summary | 摘要 |
| title | 文章标题 |
| type | 文章分类 |
| userName | 作者名称 |
时间参数规则
重要规则
1. 所有时间参数都是必传的:
startDate:必须传入,格式为 YYYY-MM-DDendDate:必须传入,格式为 YYYY-MM-DD
2. 时间参数示例(假设今天是 2026-05-14):
- 查询昨天数据:
startDate=2026-05-13&endDate=2026-05-14 - 查询前天数据:
startDate=2026-05-12&endDate=2026-05-13 - 查询近5天:
startDate=2026-05-10&endDate=2026-05-14
3. 数据同步时间:
- 数据库每日下午 18:30 同步前一日数据
- 到 19:30 推送时,昨天的数据已完全同步
4. 时间建议:
- 用户主动查询"今日文章":使用前天数据(更稳妥)
- 订阅推送(19:30):使用昨天数据(已同步完成)
分类映射表
标准分类列表
API支持以下分类:
- 人文资讯
- 知识百科
- 健康养生
- 时尚潮流
- 美食餐饮
- 乐活生活
- 旅游出行
- 搞笑幽默
- 情感心理
- 体育娱乐
- 美容美体
- 文摘精选
- 民生资讯
- 财富理财
- 科技数码
- 创投商业
- 汽车交通
- 房产楼市
- 职场发展
- 教育考试
- 学术研究
- 企业品牌
- 总排名
分类泛化映射
用户输入的关键词/主题映射到标准分类:
人文资讯
关键词:人文、历史、文化、文学、艺术、哲学、宗教、传统、非遗、民俗、人物、故事
知识百科
关键词:知识、科普、百科、常识、学习、冷知识、有趣、神奇、奥秘、原理、现象
健康养生
关键词:健康、养生、保健、医疗、疾病、医院、医生、营养、饮食、运动、健身、减肥、睡眠、心理、抑郁、焦虑
时尚潮流
关键词:时尚、潮流、穿搭、服装、配饰、奢侈品、品牌、明星、网红、街拍、妆容、发型
美食餐饮
关键词:美食、餐饮、菜谱、食谱、烹饪、做菜、餐厅、小吃、甜品、饮品、咖啡、茶、酒、外卖
乐活生活
关键词:生活、日常、家居、装修、收纳、清洁、宠物、亲子、家庭、婚姻、社交、爱好、兴趣、休闲
旅游出行
关键词:旅游、旅行、出行、景点、景区、酒店、民宿、攻略、签证、机票、自驾、户外、探险
搞笑幽默
关键词:搞笑、幽默、段子、笑话、趣闻、奇葩、沙雕、神回复、吐槽、梗、表情包
情感心理
关键词:情感、心理、恋爱、爱情、婚姻、分手、暗恋、表白、亲情、友情、情绪、治愈、疗愈
体育娱乐
关键词:体育、运动、比赛、奥运、世界杯、NBA、足球、篮球、娱乐、明星、综艺、电影、电视剧、音乐、演唱会
美容美体
关键词:美容、美体、护肤、化妆、化妆品、面膜、护肤、瘦身、塑形、医美、整形、抗衰
文摘精选
关键词:文摘、精选、好文、推荐、摘录、读书、阅读、感悟、思考、人生、哲理
民生资讯
关键词:民生、政策、法规、社保、医保、教育、就业、工资、物价、交通、环保、公益、慈善
财富理财
关键词:财富、理财、投资、基金、股票、股市、财经、金融、银行、保险、存款、赚钱、创业、赚钱
科技数码
关键词:科技、数码、手机、电脑、智能、AI、人工智能、互联网、软件、硬件、芯片、5G、新能源、电动车、特斯拉
创投商业
关键词:创投、创业、投资、商业、企业、公司、管理、营销、融资、上市、独角兽、CEO、企业家
汽车交通
关键词:汽车、车、驾驶、驾照、买车、保养、加油、停车、交通、交警、违章、事故、自驾
房产楼市
关键词:房产、楼市、房子、买房、卖房、租房、房价、装修、物业、房贷、公积金、中介
职场发展
关键词:职场、工作、求职、面试、简历、跳槽、升职、加薪、职业、同事、领导、加班、996、内卷
教育考试
关键词:教育、考试、高考、考研、考公、留学、培训、辅导、学习、成绩、学校、大学、中小学
学术研究
关键词:学术、研究、论文、科研、实验、发现、成果、学者、专家、教授、博士、硕士
企业品牌
关键词:企业、品牌、公司、营销、公关、案例、战略、转型、创新、产品、服务
总排名
关键词:总榜、全部、综合、热点、热门、爆文、10w+、推荐、最新
映射规则
1. 用户输入分析:分析用户问题中的关键词、主题、领域 2. 分类匹配:根据上述映射表,匹配最相关的分类 3. 默认分类:如果无法确定分类,默认使用"总排名" 4. 多分类处理:如果用户问题涉及多个领域,选择最核心的分类
使用示例
| 用户输入 | 匹配分类 |
|---|---|
| "推荐科技类的文章" | 科技数码 |
| "有没有健康养生方面的" | 健康养生 |
| "想看财经投资的文章" | 财富理财 |
| "今天的爆款文章" | 总排名 |
| "关于AI的文章" | 科技数码 |
| "美食推荐" | 美食餐饮 |
| "职场干货" | 职场发展 |
| "有什么好看的" | 文摘精选 |
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
公众号10w+热门文章榜单获取脚本
功能:
1. 调用API获取10w+阅读热门文章数据(按分类和时间查询)
2. 按互动数排序
3. 输出TOP榜单列表(纯文本格式)
4. 提供四维度内容分析(内容概述、热点利用、传播作用、达成效果)
使用方法:
python fetch_hot_articles.py --type "科技数码" --start_date "2024-01-01" --end_date "2024-01-02"
python fetch_hot_articles.py --type "总排名" --start_date "yesterday" --end_date ""
python fetch_hot_articles.py --type "" --start_date "daybeforeyesterday" --end_date ""
"""
import argparse
import json
import os
import sys
from datetime import datetime, timedelta
from urllib.request import Request, urlopen
from urllib.error import URLError, HTTPError
# 标准分类列表
STANDARD_CATEGORIES = [
"人文资讯", "知识百科", "健康养生", "时尚潮流", "美食餐饮", "乐活生活",
"旅游出行", "搞笑幽默", "情感心理", "体育娱乐", "美容美体", "文摘精选",
"民生资讯", "财富理财", "科技数码", "创投商业", "汽车交通", "房产楼市",
"职场发展", "教育考试", "学术研究", "企业品牌", "总排名"
]
def parse_date(date_str: str) -> str:
"""
解析日期参数
Args:
date_str: 日期字符串,支持:
- "yesterday": 昨天
- "daybeforeyesterday": 前天
- "today": 今天
- "": 不限时间
- "YYYY-MM-DD": 具体日期
Returns:
格式化的日期字符串(YYYY-MM-DD),如果为空则返回空字符串
"""
if not date_str or date_str == "":
return ""
if date_str == "yesterday":
# 昨天
yesterday = datetime.now() - timedelta(days=1)
return yesterday.strftime("%Y-%m-%d")
if date_str == "daybeforeyesterday":
# 前天
day_before_yesterday = datetime.now() - timedelta(days=2)
return day_before_yesterday.strftime("%Y-%m-%d")
if date_str == "today":
# 今天
return datetime.now().strftime("%Y-%m-%d")
# 尝试解析具体日期格式
try:
# 支持 YYYY-MM-DD 格式
dt = datetime.strptime(date_str, "%Y-%m-%d")
return dt.strftime("%Y-%m-%d")
except ValueError:
pass
# 默认返回空
return ""
def parse_count_to_int(count_str: str) -> int:
"""
将阅读数字符串转换为整数
Args:
count_str: 阅读数字符串,如 "10w+", "5w+", "1.5w+", "9w+", "1000"
Returns:
整数形式的阅读数
"""
if not count_str:
return 0
try:
count_str = str(count_str).strip()
# 处理 "10w+" 格式
if "w+" in count_str.lower():
# 提取数字部分,如 "10w+" -> "10"
num_str = count_str.lower().replace("w+", "").replace("w", "")
# 处理小数,如 "1.5w+" -> 1.5
if "." in num_str:
num = float(num_str)
return int(num * 10000)
else:
num = float(num_str)
return int(num * 10000)
# 处理 "w" 格式(没有加号)
if "w" in count_str.lower():
num_str = count_str.lower().replace("w", "")
if "." in num_str:
num = float(num_str)
return int(num * 10000)
else:
num = float(num_str)
return int(num * 10000)
# 处理纯数字
return int(float(count_str))
except:
return 0
def analyze_content(title: str, summary: str) -> str:
"""
四维度分析文章内容
Args:
title: 文章标题
summary: 文章摘要
Returns:
四维度分析文本(内容概述、热点利用、传播作用、达成效果)
"""
content = f"{title} {summary}".lower()
# 1. 内容概述
overview_keywords = {
"政策": "解读政策新规", "新规": "解读政策新规", "实施": "解读政策新规",
"调整": "分析调整内容", "变化": "分析变化趋势", "趋势": "分析趋势走向",
"技术": "介绍技术发展", "科技": "介绍科技进展", "创新": "介绍创新成果",
"市场": "分析市场动态", "投资": "分析投资机会", "理财": "提供理财建议",
"健康": "科普健康知识", "养生": "分享养生方法", "疾病": "介绍疾病防治",
"教育": "探讨教育问题", "考试": "分析考试动态", "学习": "提供学习方法",
}
overview = "分析文章核心内容"
for keyword, desc in overview_keywords.items():
if keyword in content:
overview = desc
break
# 2. 热点利用
hotspot_keywords = {
"政策": "政策热点", "新规": "政策热点", "改革": "政策热点",
"AI": "人工智能热点", "人工智能": "人工智能热点", "ChatGPT": "人工智能热点",
"新能源": "新能源热点", "电动车": "新能源热点", "特斯拉": "新能源热点",
"房价": "楼市热点", "房产": "楼市热点", "房贷": "楼市热点",
"降息": "金融热点", "加息": "金融热点", "利率": "金融热点",
"疫情": "公共卫生热点", "流感": "公共卫生热点", "病毒": "公共卫生热点",
"国产": "国产替代热点", "自主": "自主可控热点", "突破": "技术突破热点",
"财富": "财富热点", "赚钱": "财富热点", "投资": "投资热点",
}
hotspot = "结合时事热点"
for keyword, desc in hotspot_keywords.items():
if keyword.lower() in content:
hotspot = f"借用{desc}"
break
# 3. 传播作用
spread_keywords = {
"政策": "提供政策解读", "新规": "提供新规解读", "解读": "提供权威解读",
"分析": "提供专业分析", "深度": "提供深度分析", "专业": "提供专业见解",
"实用": "提供实用价值", "方法": "提供方法论", "技巧": "提供实用技巧",
"揭秘": "满足好奇心", "曝光": "满足知情权", "内幕": "满足求知欲",
"观点": "引发思考讨论", "争议": "引发话题讨论", "话题": "引发话题关注",
}
spread = "提供信息价值"
for keyword, desc in spread_keywords.items():
if keyword in content:
spread = desc
break
# 4. 达成效果
effect_keywords = {
"政策": "提升政策认知", "新规": "普及新规知识", "实施": "推动政策落地",
"分析": "增强认知水平", "深度": "深化理解层次", "专业": "建立专业认知",
"实用": "提供实践指导", "方法": "指导实际操作", "技巧": "提升实操能力",
"投资": "辅助决策判断", "理财": "提供理财参考", "赚钱": "启发创富思路",
"健康": "提升健康意识", "养生": "推广养生理念", "疾病": "增强防范意识",
}
effect = "促进信息传播"
for keyword, desc in effect_keywords.items():
if keyword in content:
effect = desc
break
# 组合输出
return f"{overview},{hotspot},{spread},{effect}"
def _get_api_key():
"""从当前环境变量获取 REDFOX_API_KEY"""
key = os.environ.get("REDFOX_API_KEY")
if not key:
print("❌ 未找到 REDFOX_API_KEY,请配置环境变量:export REDFOX_API_KEY=<your_api_key>", file=sys.stderr)
sys.exit(1)
return key
def fetch_articles_by_category(category: str, start_date: str, end_date: str, source: str = "公众号10w+阅读文章推荐-GitHub") -> list:
"""
根据分类和时间获取文章数据
使用 urllib.request 发送 HTTPS 请求
Args:
category: 分类名称(如:科技数码、健康养生、总排名等)
start_date: 开始日期(YYYY-MM-DD格式)
end_date: 结束日期(YYYY-MM-DD格式)
source: 数据来源
Returns:
文章列表
"""
# API配置
api_url = "https://redfox.hk/story/api/cozeSkill/getWxDataByCategoryAndTime"
# 获取 API Key
api_key = _get_api_key()
# 构建请求参数
params = {
"type": category if category else "总排名",
"source": source,
"startDate": start_date,
"endDate": end_date
}
# 构建请求体(JSON格式)
post_data = json.dumps(params, ensure_ascii=False).encode("utf-8")
try:
# 构建请求头
headers = {
"Content-Type": "application/json",
"X-API-KEY": api_key,
}
# 构建POST请求
req = Request(api_url, data=post_data, headers=headers, method="POST")
# 打印调试信息
print(f"\n🔍 调试信息:")
print(f" URL: {api_url}")
print(f" Method: POST")
print(f" X-API-KEY: {api_key[:8]}...(已隐藏)")
print(f" 参数: type={params['type']}, source={source}, startDate={start_date}, endDate={end_date}")
print(f" 请求体: {post_data.decode('utf-8')}")
# 发送请求
with urlopen(req, timeout=30) as response:
body = response.read().decode("utf-8")
# 解析JSON数据
data = json.loads(body)
# 检查响应数据
if data is None:
print(f"❌ 响应数据为空")
return []
# 检查业务状态码(兼容 200 和 2000)
code = data.get("code") if isinstance(data, dict) else None
if code and code not in (200, 2000):
msg = data.get("msg") or data.get("message") or "未知错误"
print(f"⚠️ API返回错误: code={code}, msg={msg}")
return []
# 从 tenWReadingRank 字段获取文章列表
if isinstance(data, dict) and "data" in data and data["data"] is not None and "tenWReadingRank" in data["data"]:
articles = data["data"]["tenWReadingRank"]
return articles if articles else []
else:
# API返回错误信息
if isinstance(data, dict) and "msg" in data:
print(f"⚠️ API返回: {data['msg']}")
return []
except HTTPError as e:
print(f"❌ HTTP错误: {e.code} {e.reason}")
return []
except URLError as e:
print(f"❌ URL错误: {e.reason}")
return []
except json.JSONDecodeError as e:
print(f"❌ JSON解析失败: {e}")
return []
except Exception as e:
print(f"❌ 数据处理失败: {e}")
return []
def process_ranking_data(articles: list) -> list:
"""
处理和排序文章数据
Args:
articles: 原始文章列表
Returns:
排序后的文章列表
"""
if not articles:
return []
# 按互动数排序(降序)
sorted_articles = sorted(
articles,
key=lambda x: parse_count_to_int(x.get("interactiveCount", "0")),
reverse=True
)
return sorted_articles
def format_summary_table(articles: list) -> str:
"""
格式化文章概览表格
Args:
articles: 文章列表
Returns:
Markdown表格文本
"""
if not articles:
return "暂无数据"
lines = []
lines.append("| 序号 | 标题 | 作者 | 阅读数 |")
lines.append("|------|------|------|--------|")
for i, article in enumerate(articles, 1):
title = article.get("title", "未知标题")
author = article.get("userName", "未知作者")
read_count = article.get("clicksCount", "0")
# 标题过长时截断
if len(title) > 30:
title = title[:30] + "..."
lines.append(f"| {i} | {title} | {author} | {read_count} |")
return "\n".join(lines)
def format_ranking_list(articles: list, limit: int = None) -> str:
"""
格式化输出文章列表(详细版)
Args:
articles: 文章列表
limit: 限制输出数量
Returns:
格式化的文本
"""
if not articles:
return "未获取到符合条件的爆款内容数据"
display_articles = articles[:limit] if limit else articles
lines = []
for i, article in enumerate(display_articles, 1):
title = article.get("title", "未知标题")
ori_url = article.get("oriUrl", "")
author = article.get("userName", "未知作者")
account_id = article.get("accountId", "")
read_count = article.get("clicksCount", "0")
publish_time = article.get("publicTime", "未知时间")
summary = article.get("summary", "")
# 内容分析
content_analysis = analyze_content(title, summary)
# 格式化输出
lines.append(f"**{i}、[{title}]({ori_url})**")
lines.append(f"📄 作者:[{author}](https://mp.weixin.qq.com/mp/profileExt?action=home&__biz={account_id}#wechat_redirect)")
lines.append(f"👀 阅读数:{read_count}")
lines.append(f"⏰ 发布时间:{publish_time}")
lines.append(f"🔍 内容分析:{content_analysis}")
lines.append("---")
lines.append("")
return "\n".join(lines)
def main():
parser = argparse.ArgumentParser(description="获取公众号10w+热门文章榜单")
parser.add_argument("--type", type=str, default="总排名",
help="分类名称(如:科技数码、健康养生、总排名等),默认:总排名")
parser.add_argument("--start_date", type=str, required=True,
help="开始日期(必传,支持:yesterday、daybeforeyesterday、YYYY-MM-DD)")
parser.add_argument("--end_date", type=str, required=True,
help="结束日期(必传,支持:yesterday、daybeforeyesterday、YYYY-MM-DD)")
parser.add_argument("--mode", type=str, default="preview",
help="输出模式:preview(预览前10条)或 full(全部展示)")
parser.add_argument("--limit", type=int, default=10,
help="预览模式下展示的数量,默认10")
parser.add_argument("--source", type=str, default="公众号10w+阅读文章推荐-GitHub",
help="数据来源")
parser.add_argument("--temp_file", type=str, default="temp_articles.json",
help="临时数据文件名")
args = parser.parse_args()
# 确定分类
category = args.type if args.type else "总排名"
# 解析日期
start_date = parse_date(args.start_date)
end_date = parse_date(args.end_date)
# 输出数据说明
print("\n💡 数据说明")
print("最新10w+阅读爆文推荐将在每日19点30分准时更新,以下数据为获取时间时的快照,和实时数据有所差别。")
print("-" * 60)
# 获取数据
print(f"\n🔍 正在获取【{category}】分类的文章数据...")
if start_date:
print(f"📅 时间范围:{start_date}" + (f" 至 {end_date}" if end_date else ""))
articles = fetch_articles_by_category(category, start_date, end_date, args.source)
if not articles:
print("\n📊 文章概览\n")
print("暂无数据")
print("\n📝 文章详情\n")
print("未获取到符合条件的爆款内容数据")
print("\n============================================================")
print("\n共获取到 0 条10w+热门文章数据")
print("💡 建议:尝试调整分类关键词或时间范围")
return
# 处理和排序数据
sorted_articles = process_ranking_data(articles)
total_count = len(sorted_articles)
# 保存数据到临时JSON文件
temp_file = args.temp_file if args.temp_file else "temp_articles.json"
with open(temp_file, 'w', encoding='utf-8') as f:
json.dump({
"category": category,
"articles": sorted_articles,
"total_count": total_count
}, f, ensure_ascii=False, indent=2)
print(f"✅ 数据已保存到临时文件:{temp_file}")
# 根据模式输出
if args.mode == "preview":
# 预览模式:展示前N条
preview_count = min(args.limit, total_count)
preview_articles = sorted_articles[:preview_count]
# 输出文章概览表格
print("\n📊 文章概览\n")
print(format_summary_table(preview_articles))
# 输出文章详情
print("\n📝 文章详情\n")
print(format_ranking_list(preview_articles))
# 统计信息
print("\n============================================================")
print(f"\n共获取到 {total_count} 条10w+热门文章数据,当前展示前 {preview_count} 条")
# 如果还有更多数据,提示用户
if total_count > preview_count:
remaining = total_count - preview_count
print(f"💡 提示:还有 {remaining} 条数据未展示,是否需要全部展示?")
# 文章数量较少提示(少于10篇)
if total_count < 10:
category_name = args.type if args.type != "总排名" else "综合"
print(f"\n💡 {category_name}赛道10w+文章较少,您可以拓展过去30天或者看看综合10w+文章~")
else:
# 完整模式:展示全部
# 输出文章概览表格
print("\n📊 文章概览\n")
print(format_summary_table(sorted_articles))
# 输出文章详情
print("\n📝 文章详情\n")
print(format_ranking_list(sorted_articles))
# 统计信息
print("\n============================================================")
print(f"\n共获取到 {total_count} 条10w+热门文章数据(已全部展示)")
# 文章数量较少提示(少于10篇)
if total_count < 10:
category_name = args.type if args.type != "总排名" else "综合"
print(f"\n💡 {category_name}赛道10w+文章较少,您可以拓展过去30天或者看看综合10w+文章~")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
公众号10w+热门文章HTML生成脚本
功能:
1. 读取API数据
2. 生成公众号风格的HTML页面
3. 支持PDF导出
使用方法:
python generate_hot_html.py --data_file data.json --output ranking.html
python generate_hot_html.py --articles '[{"title": "...", ...}]' --output ranking.html
"""
import argparse
import json
import os
from datetime import datetime
def get_rank_display(rank: int) -> str:
"""获取排名显示(奖牌或数字)"""
if rank == 1:
return "🥇"
elif rank == 2:
return "🥈"
elif rank == 3:
return "🥉"
else:
return str(rank)
def get_article_html(article: dict, rank: int, is_top: bool = False) -> str:
"""生成单篇文章的HTML"""
try:
title = article.get("title", "未知标题")
url = article.get("oriUrl", "#")
account = article.get("userName", article.get("accountId", "未知账号"))
account_id = article.get("accountId", "")
reads = article.get("clicksCount", "0")
# 处理日期
public_time = article.get("publicTime", "")
if public_time:
try:
date = str(public_time)[:10]
except:
date = ""
else:
date = ""
# 生成公众号名片链接
if account_id:
account_url = f"https://open.weixin.qq.com/qr/code?username={account_id}"
else:
account_url = "#"
top_class = " top-item" if is_top else ""
rank_display = get_rank_display(rank)
top_rank_class = " top" if is_top else ""
return f'''
<li class="article-item{top_class}">
<div class="article-body">
<div class="article-rank{top_rank_class}">{rank_display}</div>
<div class="article-content">
<a href="{url}" target="_blank" class="article-title">{title}</a>
<div class="article-info">
<span class="info-item"><a href="{account_url}" target="_blank" class="info-source-link"><span class="info-source-icon">👤</span>{account}</a></span>
<span class="info-item"><span class="info-stat">📖 阅读 <span class="info-stat-value">{reads}</span></span></span>
<span class="info-item"><span class="info-stat">📅 {date}</span></span>
</div>
</div>
</div>
</li>'''
except:
# 如果生成失败,返回空字符串
return ""
def generate_html(keyword: str, articles: list, insights: dict = None, top_n: int = 10) -> str:
"""生成完整的HTML页面"""
# 数据验证
if not articles:
articles = []
# 计算统计数据
try:
account_count = len(set(a.get("accountId", "") for a in articles if a.get("accountId")))
except:
account_count = 0
# 计算日期范围
dates = []
for a in articles:
try:
public_time = a.get("publicTime", "")
if public_time:
date_str = str(public_time)[:10] # 只取日期部分
if date_str and len(date_str) >= 10: # 确保日期格式正确
dates.append(date_str)
except:
continue
if dates:
try:
min_date = min(datetime.strptime(d, "%Y-%m-%d") for d in dates if d)
max_date = max(datetime.strptime(d, "%Y-%m-%d") for d in dates if d)
days = (max_date - min_date).days + 1
except:
days = 30
else:
days = 30
# 生成文章列表HTML
articles_html = ""
for i, article in enumerate(articles[:top_n], 1):
try:
articles_html += get_article_html(article, i, i <= 3)
except:
# 如果单篇文章生成失败,跳过
continue
# 完整的HTML模板
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>{keyword} · 公众号10w+阅读文章</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/html2pdf.js/0.10.1/html2pdf.bundle.min.js"></script>
<style>
* {{
margin: 0;
padding: 0;
box-sizing: border-box;
}}
body {{
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif;
background: #f5f5f5;
color: #333;
line-height: 1.8;
padding: 12px;
}}
.container {{
max-width: 680px;
margin: 0 auto;
background: #fff;
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.06);
overflow: hidden;
}}
.brand-header {{
background: linear-gradient(135deg, #fff 0%, #f8fff8 100%);
padding: 32px 24px 28px;
text-align: center;
border-bottom: 1px solid #eee;
}}
.brand-title {{
font-size: 26px;
font-weight: 700;
color: #1a1a1a;
margin-bottom: 8px;
letter-spacing: 1px;
}}
.brand-subtitle {{
font-size: 14px;
color: #888;
}}
.export-btn {{
display: inline-flex;
align-items: center;
gap: 4px;
background: linear-gradient(135deg, #0088ff, #0066cc);
color: #fff;
border: none;
padding: 5px 12px;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.3s ease;
box-shadow: 0 2px 8px rgba(0, 136, 255, 0.3);
}}
.export-btn:hover {{
transform: translateY(-1px);
box-shadow: 0 4px 12px rgba(0, 136, 255, 0.4);
}}
.brand-stats {{
display: flex;
justify-content: center;
gap: 32px;
margin-top: 24px;
padding-top: 20px;
border-top: 1px dashed #e5e5e5;
}}
.brand-stat {{
text-align: center;
}}
.brand-stat-num {{
font-size: 24px;
font-weight: 700;
color: rgb(0, 179, 84);
}}
.brand-stat-label {{
font-size: 12px;
color: #999;
margin-top: 4px;
}}
.content {{
padding: 24px 20px;
}}
.section-header {{
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 20px;
gap: 12px;
}}
.section-header .export-btn {{
font-size: 12px;
padding: 5px 12px;
}}
.section-right {{
display: flex;
align-items: center;
gap: 10px;
}}
.section-title {{
font-size: 18px;
font-weight: 600;
color: #1a1a1a;
display: flex;
align-items: center;
gap: 8px;
}}
.section-title::before {{
content: "";
width: 4px;
height: 20px;
background: rgb(0, 179, 84);
border-radius: 2px;
}}
.section-badge {{
background: rgba(0, 179, 84, 0.1);
color: rgb(0, 179, 84);
font-size: 12px;
padding: 4px 12px;
border-radius: 12px;
font-weight: 500;
}}
.article-list {{
list-style: none;
}}
.article-item {{
background: #fff;
border: 1px solid #eee;
border-radius: 12px;
padding: 20px;
margin-bottom: 16px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}}
.article-item:hover {{
border-color: rgb(0, 179, 84);
box-shadow: 0 4px 16px rgba(0, 179, 84, 0.12);
transform: translateY(-2px);
}}
.article-item:last-child {{
margin-bottom: 0;
}}
.article-item.top-item {{
background: linear-gradient(135deg, #fff 0%, #f8fff8 100%);
border-color: rgba(0, 179, 84, 0.3);
}}
.article-item.top-item::before {{
content: "";
position: absolute;
top: 0;
left: 0;
width: 4px;
height: 100%;
background: linear-gradient(180deg, rgb(0, 179, 84), #06a54a);
}}
.article-body {{
display: flex;
align-items: flex-start;
gap: 14px;
}}
.article-rank {{
width: 36px;
height: 36px;
background: rgb(0, 179, 84);
color: #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 14px;
flex-shrink: 0;
}}
.article-rank.top {{
background: linear-gradient(135deg, #ffd700, #ff8c00);
color: #fff;
font-size: 22px;
font-weight: normal;
}}
.article-content {{
flex: 1;
}}
.article-title {{
font-size: 17px;
font-weight: 600;
color: #1a1a1a;
line-height: 1.5;
text-decoration: none;
display: block;
margin-bottom: 12px;
cursor: pointer;
transition: color 0.2s;
}}
.article-title:hover {{
color: rgb(0, 179, 84);
}}
.article-info {{
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0;
font-size: 14px;
color: #888;
}}
.info-item {{
padding: 0 12px;
position: relative;
}}
.info-item::before {{
content: "|";
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
color: #e0e0e0;
font-size: 10px;
}}
.info-item:first-child {{
padding-left: 0;
}}
.info-item:first-child::before {{
display: none;
}}
.info-source-link {{
display: inline-flex;
align-items: center;
gap: 4px;
color: #0088ff;
text-decoration: none;
transition: color 0.2s;
}}
.info-source-link:hover {{
text-decoration: underline;
}}
.info-source-icon {{
display: inline-flex;
align-items: center;
justify-content: center;
font-size: 14px;
vertical-align: middle;
}}
.info-category {{
font-size: 11px;
color: rgb(0, 179, 84);
background: rgba(0, 179, 84, 0.1);
padding: 2px 8px;
border-radius: 4px;
font-weight: 500;
}}
.info-stat {{
display: flex;
align-items: center;
gap: 4px;
}}
.info-stat-value {{
color: #0088ff;
font-weight: 600;
}}
.footer {{
background: #fafafa;
padding: 24px;
text-align: center;
border-top: 1px solid #eee;
}}
.footer-text {{
font-size: 13px;
color: #888;
}}
.footer-copy {{
font-size: 11px;
color: #bbb;
margin-top: 8px;
}}
@media (max-width: 480px) {{
body {{
padding: 0;
}}
.container {{
border-radius: 0;
}}
.brand-stats {{
gap: 20px;
}}
.article-info {{
gap: 8px;
}}
}}
@media print {{
.export-btn {{
display: none !important;
}}
.container {{
padding: 15mm !important;
}}
.brand-header {{
padding: 8mm 10mm !important;
margin-bottom: 8mm !important;
}}
.brand-stats {{
padding: 6mm !important;
gap: 10px !important;
}}
.brand-stat {{
padding: 4mm 6mm !important;
}}
.section-header {{
padding: 6mm 0 !important;
}}
.article-item {{
padding: 6mm 8mm !important;
margin-bottom: 4mm !important;
}}
.footer {{
padding: 8mm !important;
}}
}}
</style>
</head>
<body>
<div class="container">
<div class="brand-header">
<h1 class="brand-title">{keyword} · 10w+阅读文章</h1>
<p class="brand-subtitle">每日推送公众号10w+爆款内容,解析流量密码</p>
<div class="brand-stats">
<div class="brand-stat">
<div class="brand-stat-num">{top_n}</div>
<div class="brand-stat-label">篇爆款文章</div>
</div>
<div class="brand-stat">
<div class="brand-stat-num">{account_count}</div>
<div class="brand-stat-label">个账号</div>
</div>
<div class="brand-stat">
<div class="brand-stat-num">{days}</div>
<div class="brand-stat-label">天内热文</div>
</div>
</div>
</div>
<div class="content">
<div class="section-header">
<h2 class="section-title">TOP{top_n} 爆款文章</h2>
<div class="section-right">
<span class="section-badge">阅读量排序</span>
<button class="export-btn" onclick="exportToPDF()">📥 导出PDF</button>
</div>
</div>
<ul class="article-list">
{articles_html}
</ul>
</div>
<div class="footer">
<p class="footer-text">公众号10w+阅读文章,每日更新最新爆文内容</p>
<p class="footer-copy">备注:互动数据为入库快照,实时数据可能持续增长</p>
</div>
</div>
<script>
function exportToPDF() {{
const element = document.querySelector('.container');
const button = document.querySelector('.export-btn');
button.style.display = 'none';
// 计算内容高度,决定PDF尺寸
const contentHeight = element.scrollHeight;
const contentWidth = element.scrollWidth;
// 根据内容比例决定纸张尺寸,mm为单位,1mm ≈ 3.78px
const pdfWidth = Math.max(210, Math.ceil(contentWidth / 3.78) + 20);
const pdfHeight = Math.max(297, Math.ceil(contentHeight / 3.78) + 20);
const opt = {{
margin: 0,
filename: '{keyword}_爆款内容分析.pdf',
image: {{ type: 'jpeg', quality: 0.95 }},
html2canvas: {{
scale: 2,
useCORS: true,
logging: false,
scrollX: 0,
scrollY: 0
}},
jsPDF: {{
unit: 'mm',
format: [pdfWidth, pdfHeight],
orientation: pdfWidth > pdfHeight ? 'landscape' : 'portrait'
}},
pagebreak: {{ mode: 'none' }}
}};
html2pdf().set(opt).from(element).save().then(() => {{
button.style.display = 'inline-flex';
}});
}}
</script>
</body>
</html>'''
return html
def main():
parser = argparse.ArgumentParser(description="生成公众号10w+热门文章HTML")
parser.add_argument("--temp_file", default="temp_articles.json", help="临时JSON文件路径")
parser.add_argument("--output", default="ranking.html", help="输出文件路径")
parser.add_argument("--display_count", type=int, default=None, help="要展示的文章数量(如果不指定,则展示所有文章)")
args = parser.parse_args()
try:
# 从临时JSON文件读取数据
try:
with open(args.temp_file, "r", encoding="utf-8") as f:
temp_data = json.load(f)
keyword = temp_data.get("keyword", "热门文章")
articles = temp_data.get("articles", [])
if not isinstance(articles, list):
articles = []
except FileNotFoundError:
print(f"错误: 临时文件不存在 - {args.temp_file}", file=sys.stderr)
return 1
except json.JSONDecodeError:
print(f"错误: 临时文件格式错误 - {args.temp_file}", file=sys.stderr)
return 1
except Exception as e:
print(f"错误: 读取临时文件失败 - {str(e)}", file=sys.stderr)
return 1
if not articles:
print(f"错误: 临时文件中没有文章数据", file=sys.stderr)
return 1
# 根据display_count参数确定要展示的文章数量
display_count = args.display_count if args.display_count is not None else len(articles)
display_articles = articles[:display_count]
print(f"✅ 从临时文件读取到 {len(articles)} 条文章数据,本次展示 {len(display_articles)} 条")
# 生成HTML(使用display_articles而不是articles)
try:
html_content = generate_html(keyword, display_articles, None, len(display_articles))
except Exception as e:
print(f"错误: 生成HTML失败 - {str(e)}", file=sys.stderr)
return 1
# 写入文件
try:
with open(args.output, "w", encoding="utf-8") as f:
f.write(html_content)
except Exception as e:
print(f"错误: 写入文件失败 - {str(e)}", file=sys.stderr)
return 1
print(f"✅ HTML文件已生成: {args.output}")
return 0
except Exception as e:
print(f"错误: {str(e)}", file=sys.stderr)
return 1
if __name__ == "__main__":
import sys
sys.exit(main())