playlet-wechat-feed
短剧-公众号信息源 — 每日扫描公众号短剧爆款文章,按阅读量筛选热门内容,智能聚类题材方向后生成包含封面图、互动数据与创作洞察的HTML日报。支持按题材(穿越/霸总/重生等)、公众号、时间范围定向查询。⚠️查询前脚本先做输入校验:关键词需命中短剧题材词库(topic_keywords 中规定的题材名+全部相关词,如「打脸」命中逆袭题材相关词),命中后直接使用该关键词查询数据;不满足时提醒'关键词不满足查询条件'并推荐相关词,且**不发起接口请求**;日期超出有效查询范围时提醒并自动回退最近有数据日期,无需用户确认。**无数据确认制**:查询无匹配数据或数
Install
npx skills add https://github.com/redfox-data/redfox-community/tree/main/skills/playlet-wechat-feed
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install redfox-data-redfox-community@llmmart
git clone https://github.com/redfox-data/redfox-community.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole redfox-data/redfox-community collection as a plugin from our marketplace. Git is the plain clone.
README
短剧-公众号信息源 / playlet-wechat-feed
简介
短剧-公众号信息源是一款专为短剧创作者和内容运营打造的公众号爆款追踪工具。每日自动扫描公众号短剧内容,按阅读量筛选热门作品,智能聚类题材方向后生成可视化 HTML 日报与创作趋势分析。
核心价值
- 🔥 发现当日公众号短剧爆款文章,精准定位高热度作品
- 📊 获取按题材智能聚类的热门内容,一目了然掌握热点分布
- 📈 分析爆款标题特征与创作趋势,挖掘流量密码
- 🔔 开启每日订阅,自动产出日报,建立情报体系
适用对象
- ✍️ 短剧编剧 — 精准把握题材风口,提升选题命中率
- 📱 内容运营 — 每日追踪公众号短剧爆款,驱动内容决策
- 🏢 MCN 机构 — 监测行业动态,管理矩阵账号内容方向
- 📝 公众号号主 — 发现对标账号和爆款内容,优化创作策略
功能特性
核心功能
- 爆款发现 — 从公众号短剧文章中按阅读量筛选热门内容,精准定位高热度短剧作品
- 题材聚类 — 自动识别题材方向(穿越/霸总/重生/悬疑/甜宠/逆袭/年代/战神/古装),每日题材分类由内容动态决定
- 智能查询 — 默认查询全部短剧,数据不足时自动扩展题材批量查询,节省调用额度
- 自定义查询 — 支持指定任意题材、公众号、关键词定向查询,灵活覆盖任意短剧细分方向
- 创作洞察 — 分析爆款标题特征、题材趋势、公众号表现,深度挖掘创作规律
- 可视化日报 — 深色主题 HTML 日报,包含封面图、互动数据与文章直达链接
- 一键订阅 — 开启后每日自动产出日报,保存在本地文件夹
特色亮点
- ⚡ 批量查询 — 所有题材通过批量接口一次性查询,高效节省接口调用次数
- 🧠 智能聚类 — 9 大题材自动分类,每日动态调整,不固化
- 💾 缓存机制 — 1 小时有效期,避免重复请求,快速查看近期结果
- 📅 日期智能判断 — 自动检测目标日期有效性,避免无效调用
密钥获取与安全说明
- 本技能需要使用环境变量:
REDFOX_API_KEY。 REDFOX_API_KEY由 红狐 hub(https://redfox.hk)提供。- 请前往 红狐 hub 注册账号,获取
REDFOX_API_KEY。 - 配置设备环境变量
REDFOX_API_KEY后使用本技能。 - 在提供密钥前,请先确认密钥来源、可用范围、有效期及是否支持重置/撤销。
- 禁止在代码、提示词、日志或输出文件中硬编码/明文暴露密钥。
使用指南
直接用自然语言描述需求,无需记忆命令。
常用说法速查
| 意图 | 示例话术 | 效果 |
|---|---|---|
| 查询最新日报 | "查询今天的短剧公众号日报" | 生成最新一期可视化日报 |
| 按题材查询 | "穿越题材的短剧"、"查询霸总和甜宠的短剧" | 定向获取指定题材的爆款内容 |
| 按时间查询 | "这个月的短剧趋势怎么样"、"6月的短剧爆款" | 分析一段时间内的内容趋势 |
| 历史数据回顾 | "6月10号的短剧公众号日报有吗" | 查看指定日期的爆款数据 |
| 组合查询 | "穿越题材6月短剧" | 精准定位特定题材+时间范围 |
| 开启订阅 | "开启短剧日报每日订阅" | 每日自动产出并保存日报 |
| 快速查看缓存 | "用缓存数据查看上次的短剧结果" | 1小时内免调用快速查看 |
输出示例
日报生成后,终端输出题材分类表格与创作趋势分析报告,同时生成深色主题 HTML 可视化日报并自动在浏览器中打开。HTML 日报包含:
- 题材卡片布局,清晰展示各题材分布
- 每篇文章展示封面图、标题、公众号名称、阅读量、点赞数、评论数(各项为 0 时自动隐藏该字段)
- 统计面板:题材数、文章数、平均阅读、总阅读
以下为 2026-06-15 真实输出样例:
短剧-公众号信息源 · 2026-06-15 日报
扫描 176 篇热门短剧文章,聚类 6 个题材方向
题材概览
| 题材 | 数量 | 占比 | 爆款亮点 |
|---|---|---|---|
| #其他 | 156篇 | 88.6% | 《价值升维,短剧与明星双向奔赴的2.0时代》2.3w阅读,AI短剧工具类内容大量涌现 |
| #甜宠 | 7篇 | 4.0% | 《热植物语》温馨睡前故事,均阅读800+,受众稳定 |
| #霸总 | 6篇 | 3.4% | 克拉拉转型短剧演员引热议,单篇最高4905阅读 |
| #悬疑 | 3篇 | 1.7% | 《短剧男演员去世真相》3801阅读,八卦向内容互动强 |
| #穿越 | 3篇 | 1.7% | 陕西短剧基地千万实景遇冷,产业观察类内容受关注 |
| #古装 | 1篇 | 0.6% | 《古装发型提示词,附图》1058阅读,AI创作辅助类单篇爆发 |
创作趋势分析
一、新兴起量信号
- 🔥 #古装 — 仅1篇但点赞率达3.6%(38赞/1058阅读),AI辅助创作类工具内容互动远超均值,提示词/工作流类内容有持续爆发潜力
- 🔥 #悬疑 — 仅3篇但头部阅读达3801,八卦揭秘+短剧圈内幕的组合标题互动效率高于大盘均值
二、爆款标题特征
| 特征模式 | 出现次数 | 典型案例 | 平均阅读 |
|---|---|---|---|
| 感叹号情绪钩子(!) | 93次 | 《OiiOii 2.0重磅升级,短剧带货真的要杀疯了...》 | 1374 |
| 疑问号悬念钩子(?) | 55次 | 《长短剧边界消融,演员在千亿短剧新局有何机遇?》 | 1325 |
| "N部"清单推荐体 | 13次 | 《5部高分上头短剧合集!霸总甜宠、都市治愈》 | 1072 |
| AI+工具/平台名 | 15次 | 《全网7亿播放的AI短剧,背后的神级制作工具我找到了!》 | 约6500 |
三、核心公众号榜
暂无核心公众号数据(本日接口未返回 accountName 字段)
四、题材趋势报告
题材:#甜宠 作品数:7篇 平均阅读:约900 头部作品:《热植物语》迪克羊仔(温馨甜宠睡前故事)— 1258阅读
题材特征:甜宠题材以"睡前故事""情头""宝藏剧推荐"为主要内容形态,标题普遍带有"甜""治愈""圆满"等情绪关键词,受众黏性高但流量天花板较低,阅读规模整体偏中腰部。 创作建议:可结合"CP向"二创内容、"甜宠+其他题材"复合标签(如甜宠×古装、甜宠×穿越)破圈,标题加入"闭眼追""宝藏""结局超甜"等完结承诺类钩子提升点击。
五、#霸总
题材:#霸总 作品数:6篇 平均阅读:约2911 头部作品:《"亚洲第一美女"克拉拉,被豪门抛弃,转型当短剧演员!》— 4905阅读
题材特征:霸总题材本日热度主要由"明星入局短剧"的八卦新闻驱动,而非传统霸总剧情推荐。"豪门""转型""被抛弃"等反差词构成核心流量钩子,汉南拍摄地话题也带动了在地化传播。 创作建议:可借势明星/演员话题切入霸总题材,标题结构采用"身份反差+转折"公式(如"被XX抛弃,转型XX"),同时结合"高分合集""上头短剧"清单体做长尾流量。
六、#悬疑
题材:#悬疑 作品数:3篇 平均阅读:约2047 头部作品:《短剧男演员去世真相,安以轩复出,侯明昊被拉出试水…》— 3801阅读
题材特征:悬疑题材本日以"圈内八卦+真相揭秘"形式呈现,标题普遍采用多个明星名串联+悬念问号的钩子结构;另有银发反诈AI微短剧(1718阅读)等政策向内容,整体数量少但单篇互动高于大盘均值。 创作建议:悬疑题材公众号端更适合"内幕揭秘""真相还原"等非虚构方向,标题可堆叠多个名人/事件名制造信息密度感,同时关注"反诈""社会议题"等政策风口,容易获得平台流量加持。
七、跨题材对比建议
- #霸总 × #甜宠 — 建议同步关注"霸总甜宠"复合标签的联动创作,本日《5部高分上头短剧合集!霸总甜宠、都市治愈》(2606阅读)已验证融合题材的合集形式有效,可进一步拆解两题材受众重叠度
- #AI短剧(其他类内隐主题)× 全题材 — 本日38篇AI短剧相关内容均阅读2630,远超大盘1994均值,AI工具+任意题材的"制作教程/工具测评"方向是当前显著流量洼地,建议各题材创作者关注AI制作工作流内容
日报地址:C:\Users\马祯\Downloads\QoderReports\短剧公众号日报_2026-06-15.html
数据说明:每日15:00更新昨天的数据
使用场景
| 场景 | 角色 | 示例问法 | 收益 |
|---|---|---|---|
| 选题调研 | 短剧编剧 | "最近什么短剧题材最火?帮我分析下穿越和重生" | 精准把握题材风口,提升选题命中率 |
| 日报追踪 | 公众号运营 / MCN | "开启短剧日报订阅,每天帮我追踪公众号爆款" | 建立团队短剧情报体系,驱动内容决策 |
| 竞品分析 | 品牌方 / 投放经理 | "查询霸总题材6月的短剧公众号表现" | 及时调整投放策略,优化内容差异化 |
| 趋势复盘 | 内容总监 / 数据分析师 | "对比这个月和上个月的短剧趋势变化" | 掌握中长期趋势,指导内容战略规划 |
Skill manifest
短剧-公众号信息源
📝 简介
短剧-公众号信息源是一款专为短剧创作者和内容运营设计的公众号爆款追踪工具,每日自动扫描公众号短剧内容,按阅读量筛选热门作品,智能聚类题材方向后生成可视化 HTML 日报与创作趋势分析。
通过简单的指令,你可以:
- 🔥 发现当日公众号短剧爆款文章
- 📊 获取按题材智能聚类的热门内容
- 📈 分析爆款标题特征与创作趋势
- 🔔 开启每日订阅,自动产出日报
适用于短剧编剧、内容运营、MCN 机构、公众号号主等需要追踪公众号短剧热点的场景。
⚠️ 重要提醒:数据每日 15:00 更新前一天数据(实际可能延迟,以脚本真实探活为准)。查询前脚本先做输入校验:关键词需命中短剧题材词库(
topic_keywords中规定的题材名+全部相关词,如「打脸」命中逆袭题材相关词),命中后直接使用该关键词查询数据;不满足时提醒"关键词不满足查询条件"并推荐相关词,不发起接口请求;日期超出有效查询范围时提醒并自动回退最近有数据日期,无需用户确认。无数据确认制(v2.3):查询无匹配数据或全量数据不足时,禁止自动发起任何额外查询(禁止自动降级全量、禁止自动扩展题材),必须先向用户展示推荐题材关键词并等待确认,确认后才可按推荐词重新查询。
✨ 功能特性
🎯 核心功能
| 功能模块 | 能力描述 | 核心价值 |
|---|---|---|
| 爆款发现 | 从公众号短剧文章中按阅读量筛选热门内容 | 精准定位高热度短剧作品 |
| 题材聚类 | 自动识别题材方向(穿越/霸总/重生/悬疑等) | 每天题材分类由内容动态决定 |
| 智能查询 | 默认查询全部短剧;数据不足时提示推荐题材并询问用户,确认后才扩展查询 | 节省接口额度,不自动消耗额外查询 |
| 自定义查询 | 用户可指定任意题材/公众号/关键词定向查询;无匹配数据时不自动查询,询问用户是否按推荐词重查 | 灵活覆盖任意短剧细分方向 |
| 创作洞察 | 分析爆款标题特征、题材趋势、公众号表现 | 深度挖掘创作规律 |
| 可视化日报 | 深色主题HTML,封面图+互动数据(为0时隐藏)+文章直链 | 直观展示每日短剧热点 |
| 一键订阅 | --subscribe 开启每日自动产出 |
日报自动攒在本地文件夹 |
✨ 技术亮点
- ⚡ 探活式日期预检:调用前先用轻量请求(无keyword, pageSize=1)真实探测目标日期是否有数据,替代纯本地时钟推断,自动拦截无效查询,避免浪费API额度
- 🧭 前置输入校验:查询前先判断用户的分类/关键词是否命中短剧题材词库(
topic_keywords中规定的题材名+全部相关词,命中后直接使用该关键词查询数据)、日期是否在有效查询范围;不满足时提醒"关键词不满足查询条件"并推荐相关分类和关键词,不发起接口请求 - 🔄 自动回退:
--latest自动向前回退最多7天,找到最近有数据的日期再出日报 - 🛑 无数据确认制:查询无匹配数据 / 全量数据不足时,不自动发起任何额外查询(不自动降级全量、不自动扩展题材),输出推荐题材关键词并等待用户确认,确认后才重新查询
- 🧠 智能聚类:9 大题材自动分类(穿越/霸总/重生/悬疑/甜宠/逆袭/年代/战神/古装)
- 🔒 安全接入:通过 API Key 鉴权,无需账号密码
- 💾 缓存机制:1 小时有效期,避免重复扣费
🔑 安装配置
前置条件
- Python 3 运行环境
- 红狐Hub API Key(前往 红狐Hub 官网 注册获取,格式为
ak_xxxxxxxx)
环境变量配置
数据查询接口通过请求头 X-API-KEY 鉴权,Key 从环境变量 REDFOX_API_KEY 获取。
| 变量名 | 必填 | 说明 |
|---|---|---|
REDFOX_API_KEY |
是 | 红狐Hub API 访问密钥 |
配置方式:
- macOS/Linux:将
export REDFOX_API_KEY=<值>追加到~/.zshrc或~/.bashrc,然后source使其生效 - Windows:
[Environment]::SetEnvironmentVariable("REDFOX_API_KEY", "<值>", "User")(需重启终端) - 配置后验证:
echo $REDFOX_API_KEY(macOS/Linux)或echo %REDFOX_API_KEY%(Windows)
查询接口调用时通过
source字段同步记录(值为短剧公众号信息源-GitHub),无需额外请求保存接口。
📖 使用指南
基础使用
1. 输入与日期预检(必须执行,先于任何接口调用)
⛔ 核心规则:关键词/分类不满足短剧题材词库时,不发起任何接口请求
数据更新规则:每日 15:00 更新前一天的数据(实际可能延迟,以脚本真实探活为准)
- 15:00 前:估算最新可用日期 = T-2(前天)——仅作初始起点
- 15:00 后:估算最新可用日期 = T-1(昨天)——仅作初始起点
执行流程(每次查询前强制执行):
- 关键词/分类前置校验:判断用户输入的分类/关键词是否符合短剧题材词库
- 不满足时提醒"关键词不满足查询条件",推荐相关分类和关键词,不发起接口请求,直接停止并引导用户改用推荐词
- 混合词场景:保留有效关键词继续查询,无效关键词自动忽略并提示
- 全部无效:不请求接口,停止并推荐相关词
- 日期前置校验:判断目标日期格式是否有效、是否晚于今天;超出范围时提醒并推荐最近可用日期
- 真实探活:用
pageSize=1不带 keyword 的轻量请求实际探测目标日期是否有数据,以接口返回为准(替代纯本地时钟推断) - 日期兜底:目标日期未更新或超过查询时间范围时,自动向前回退获取最近时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动获取最近时间范围数据",无需用户确认
--latest模式同样自动向前回退(最多7天)定位最近有数据的日期- 无数据确认制(v2.3):题材关键词查询无匹配数据 / 全量数据不足(<100条)时,禁止自动发起任何额外查询(禁止自动降级全量、禁止自动扩展题材),必须向用户展示推荐题材关键词并询问"是否按推荐题材重新查询",得到用户确认后才可发起查询
- 若回退 7 天内均无数据,提示用户稍后再试或联系数据源确认更新状态
示例对话:
用户:查询今天的短剧公众号日报
Agent:(执行 --latest,脚本自动向前回退定位最近有数据的日期,直接生成日报)
用户:查询"智能辅助驾驶"题材的短剧文章
Agent:⚠️ 关键词 ['智能辅助驾驶'] 不满足短剧查询条件(短剧按题材/剧情词匹配标题,非短剧题材词大概率无结果)
💡 推荐相关分类和关键词:穿越、霸总、重生、甜宠、悬疑、逆袭、年代、战神、古装、都市
🛑 关键词均不满足短剧查询条件,未发起任何接口请求。请使用推荐题材词重新查询。
用户:查询"古装"题材的短剧文章(该日期无匹配数据)
Agent:📭 未查询到相关数据 [原因: 查询条件(题材词)在该日期无匹配作品]
🛑 未发起任何额外查询(禁止自动降级全量 / 自动扩展题材)
💡 推荐题材:穿越、霸总、重生、甜宠、悬疑、逆袭、年代、战神、古装、都市
❓ 是否按推荐题材(如 穿越/霸总)重新查询?请确认后我再查询。
2. 生成爆款日报
# 生成最新一期日报(用户确认后,自动跳过无数据日期,不扣积分)
python3 "$SKILL_PATH/assets/daily_report.py" --latest
# 生成指定日期日报(历史日期已有数据,无需确认)
python3 "$SKILL_PATH/assets/daily_report.py" --date 2026-06-10
# 自定义题材查询(用户指定方向;无匹配/数据不足时不自动扩展,询问用户确认后重查)
python3 "$SKILL_PATH/assets/daily_report.py" --topics "穿越,霸总,重生,悬疑" --latest
# 订阅 / 取消订阅
python3 "$SKILL_PATH/assets/daily_report.py" --subscribe
python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe
查询策略:默认查询全部短剧内容(pageSize=200)。无数据确认制(v2.3):数据不足(小于100条)时不再自动扩展题材,脚本提示推荐题材(穿越→霸总→重生→悬疑→甜宠→逆袭)并等待用户确认,确认后才通过
--topics重新查询;用户自定义题材时仅使用用户提供的列表。查询前自动探活目标日期;空结果自动重试1次。
3. 创作趋势分析
日报生成后,必须基于聚类结果自动执行创作趋势分析:
- 读取题材聚类结果,选取 TOP 5 热门题材
- 分析每个题材的爆款数量、平均互动数据、头部作品特征
- 识别新兴起量题材(数量少但互动高)
- 输出结构化创作趋势报告
生成的 HTML 日报保存在 ~/Downloads/QoderReports/,自动浏览器打开。终端同步输出题材分类表格 + 创作趋势分析报告。
高级使用
自定义题材查询
除默认短剧日报外,用户可指定任意题材组合进行定向查询:
# 查询穿越题材热门短剧文章
python3 "$SKILL_PATH/assets/daily_report.py" --topics "穿越,时空,重生"
# 查询霸总/甜宠题材
python3 "$SKILL_PATH/assets/daily_report.py" --topics "霸总,甜宠,总裁,虐恋"
# 查询悬疑/反转题材
python3 "$SKILL_PATH/assets/daily_report.py" --topics "悬疑,推理,反转,惊悚"
自定义查询逻辑:
- 前置校验(v2.2):查询前先判断关键词/分类是否符合短剧题材词库(穿越/霸总/重生/甜宠/悬疑/逆袭/年代/战神/古装等)。不满足时明确提醒"关键词不满足短剧查询条件",并推荐相关分类和关键词(优先从无效词中提取题材词,再补热门题材),且不发起接口请求,引导用户改用推荐词查询
- 无效词自动忽略:混合词场景下保留有效关键词继续查询,无效关键词自动忽略并提示;全部无效时不请求接口,直接停止并推荐相关词
- 无数据确认制(v2.3):用户指定的关键词/题材无匹配数据时,禁止自动降级为全量查询、禁止自动扩展题材,脚本停止并输出推荐题材关键词,Agent 必须先询问用户"是否按推荐题材重新查询",得到确认后才可发起查询
- 数据不足确认制:未指定题材的默认查询,全量数据不足(<100条)时同样不自动扩展题材,仅提示推荐题材并询问用户,已获取的数据仍正常生成日报
- 用户提供的所有题材通过批量接口一次性查询,无需逐个调用
- 查询结果自动去重,题材聚类、趋势分析均基于查询结果生成
时间范围查询
# 查询 6 月短剧爆款
python3 "$SKILL_PATH/assets/daily_report.py" \
--start-time "2026-06-01 00:00:00" \
--end-time "2026-06-30 23:59:59"
# 查询近 7 天短剧
python3 "$SKILL_PATH/assets/daily_report.py" \
--start-time "2026-06-10 00:00:00" \
--end-time "2026-06-17 23:59:59"
订阅功能
# 开启每日订阅 — 日报自动产出并保存至 ~/Downloads/QoderReports/
python3 "$SKILL_PATH/assets/daily_report.py" --subscribe
# 取消订阅
python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe
命令速查
| 命令/参数 | 功能 | 默认值 |
|---|---|---|
--latest |
自动向前回退最多7天,定位最近有数据的日期,跳过无数据区间 | — |
--date YYYY-MM-DD |
指定日期查询(未更新或超范围时自动回退最近有数据的日期) | 今天 |
--topics "题材1,题材2" |
自定义题材关键词,逗号分隔。查询前先校验是否符合短剧题材词库,不满足时提醒+推荐相关词并不请求接口;无匹配数据时不自动查询,询问用户确认后才重查 | 短剧 |
--start-time |
自定义开始时间 YYYY-MM-DD HH:MM:SS | — |
--end-time |
自定义结束时间 YYYY-MM-DD HH:MM:SS | — |
--count N |
扫描文章数量,满足即停 | 200 |
--output-dir |
输出目录 | ~/Downloads/QoderReports |
--api-key |
指定 API Key(覆盖环境变量) | — |
--subscribe |
开启每日订阅 | — |
--unsubscribe |
关闭每日订阅 | — |
📊 输出格式(强制执行)
⛔ 严格执行规则:
- 以下模板是唯一合法输出格式,禁止任何自由发挥、省略、简化或重新组织
- 禁止输出模板中未定义的额外内容(如"我来帮你…""以下是…"等口语化文字)
- 禁止合并、跳过任何板块,即使某板块数据为"暂无"也必须保留该板块标题
- 日报生成后,对话回复只能包含以下内容,不得包含其他任何文字
每次运行日报后,对话输出必须严格按以下模板原样输出(仅替换 {...} 占位符):
## 短剧-公众号信息源 · {日期} 日报
**扫描 {N} 篇热门短剧文章,聚类 {M} 个题材方向**
---
### 题材概览
| 题材 | 数量 | 占比 | 爆款亮点 |
|------|------|------|---------|
| #{题材名} | {N}篇 | {X}% | 《{头部作品标题}》{阅读数}阅读,{该题材当日内容特征简述} |
| ... | ... | ... | ... |
---
### 创作趋势分析
**一、新兴起量信号**
- 🔥 **#{题材}** — 仅{N}篇但{核心互动指标描述(如:均阅读X+、点赞率X%等)},{起量原因/内容特征分析}
(若无新兴起量信号,输出:暂无新兴起量信号)
> 新兴起量判断标准:作品数≤3篇但头部阅读超过大盘均值,或互动率(点赞/阅读)显著高于其他题材
**二、爆款标题特征**
| 特征模式 | 出现次数 | 典型案例 | 平均阅读 |
|---------|---------|---------|---------|
| {标题结构特征描述(如:感叹号情绪钩子(!)、"N部"清单推荐体、AI+工具/平台名等)} | {N}次 | 《{标题}》 | {X} |
| ... | ... | ... | ... |
(若无标题数据,输出:暂无爆款标题数据)
> 标题特征分析维度:标点符号使用(!/?/…)、数字清单体(N部/N条)、关键词类型(AI/明星/工具)、情绪钩子结构(反差词/悬念词/承诺词)
**三、核心公众号榜**
| 公众号 | 作品数 | 总阅读 | 代表作 |
|--------|--------|--------|--------|
| @{公众号} | {N}篇 | {X}w | 《{作品}》 |
| ... | ... | ... | ... |
(若无公众号数据,输出:暂无核心公众号数据(本日接口未返回 accountName 字段))
**四、题材趋势报告**
**题材**:#{题材1}
**作品数**:{N}篇
**平均阅读**:{X}
**头部作品**:《{标题}》— {阅读}阅读
**题材特征**:{基于当日数据描述该题材的内容形态、标题特征、受众画像、流量天花板等}
**创作建议**:{基于数据给出可执行的创作方向、标题公式、题材融合建议等}
**五、#{题材2}**
(同上格式)
**六、#{题材3}**
(同上格式)
> 题材趋势报告选取 TOP 3 题材(排除"其他")逐一展开分析,每个题材必须包含「题材特征」和「创作建议」两个子模块
**七、跨题材对比建议**
- **{题材A} × {题材B}** — {两题材的联动创作建议,基于当日数据中发现的跨题材信号}
- **{主题线索(如:AI短剧)} × 全题材** — {当日数据中发现的跨题材共性趋势及创作机会}
(若无建议,输出:暂无跨题材对比建议)
---
**日报地址**:{HTML文件绝对路径}
> 数据说明:每日15:00更新昨天的数据
以上格式为强制规范,所有字段不可省略,板块标题(一、二、三、四、五、六、七)必须保留。若某模块无数据则在该板块内标注"暂无",不得删除板块本身。
输出质量要求:
- 题材概览的「爆款亮点」必须包含该题材当日的内容特征简述,不能仅列出头部作品
- 爆款标题特征必须基于实际数据归纳,特征模式需具体可操作(如"感叹号情绪钩子"而非"情绪化标题")
- 题材趋势报告的「题材特征」和「创作建议」必须基于当日数据,不能套用通用描述
- 跨题材对比建议必须从当日数据中发现真实联动信号,不能凭空推测
- HTML 日报中各项互动数据(阅读量 👁 / 点赞数 👍 / 评论数 💬)为 0 时不展示该字段,只展示有实际数据的指标
🎯 使用场景
场景一:短剧编剧选题调研
角色:短剧编剧
需求:了解当前公众号短剧哪些题材最火,为下一部作品选题
使用方式:
- 运行默认日报,查看题材概览和趋势分析
- 关注新兴起量信号,发现蓝海题材
- 分析爆款标题特征,学习流量密码
预期收益:精准把握题材风口,提升选题命中率
场景二:内容运营日报追踪
角色:公众号运营 / MCN 运营
需求:每日追踪短剧公众号爆款,形成团队内部情报
使用方式:
- 开启
--subscribe订阅,每日自动产出日报 - 按题材查询(
--topics "穿越,霸总")聚焦团队关注方向 - 分析核心公众号榜,发现优质对标账号
预期收益:建立团队短剧情报体系,驱动内容决策
场景三:竞品分析
角色:品牌方 / 投放经理
需求:监测竞品公众号的短剧推广表现
使用方式:
- 用
--topics查询竞品相关关键词 - 分析竞品题材分布和阅读数据
- 对比自身与竞品的题材布局差异
预期收益:及时调整投放策略,优化内容差异化
场景四:创作趋势复盘
角色:内容总监 / 数据分析师
需求:复盘一段时间内的短剧创作趋势变化
使用方式:
- 使用
--start-time和--end-time查询指定时间段 - 对比不同日期的题材分布和爆款特征
- 识别持续增长题材和衰退题材
预期收益:掌握中长期趋势,指导内容战略规划
🏗️ 项目架构
目录结构
短剧-公众号信息源/
├── SKILL.md # 主文档(Skill 定义)
├── README.md # 快速开始指南
├── assets/
│ └── daily_report.py # 主脚本
├── scripts/
│ └── playlet_wechat_daily.py # 脚本副本
└── references/
├── core_workflow.md # 核心执行流程、日期预检、输出格式模板、错误处理
└── examples.md # 使用示例与常见用法组合
技术栈
| 组件 | 技术 | 说明 |
|---|---|---|
| 运行环境 | Python 3 | 脚本语言 |
| 数据源 | 红狐Hub API | 公众号短剧数据接口 |
| 鉴权方式 | X-API-KEY | 请求头鉴权 |
| 输出格式 | HTML/CSS | 深色主题可视化日报 |
| 缓存机制 | JSON 文件 | 1 小时有效期 |
平台适配说明
本 skill 基于"短剧-抖音信息源"改造,针对公众号平台做了以下核心适配:
| 维度 | 抖音版本 | 公众号版本(本 skill) |
|---|---|---|
| 平台标识 | platform: 1 |
platform: 0 |
| 核心指标 | 点赞量(likeCount) | 阅读量(readCount) |
| 账号字段 | userName | accountName |
| 展示指标 | 点赞、评论、分享 | 阅读(👁)、点赞(👍)、评论(💬),为0时隐藏该字段 |
| 主题色 | 粉色 #FB7299 | 绿色 #07C160 |
| 图标 | 🔗👍⭐ | 👁👍💬 |
| 文件命名 | 短剧抖音日报 | 短剧公众号日报 |
| 缓存文件 | playlet_douyin_data.json | playlet_wechat_data.json |
核心代码差异:
# 排序逻辑 — 公众号以阅读量为核心排序指标
# 抖音: unique_items.sort(key=lambda x: x.get("likeCount", 0), reverse=True)
# 公众号: unique_items.sort(key=lambda x: x.get("readCount", 0), reverse=True)
# 文件命名
# 抖音: f"短剧抖音日报_{date_str}.html" / "playlet_douyin_data.json"
# 公众号: f"短剧公众号日报_{date_str}.html" / "playlet_wechat_data.json"
保持一致的部分:输入与日期预检机制(关键词不满足不请求接口)、无数据确认制(不自动降级/不自动扩展,询问后确认再查)、数据更新规则、题材聚类算法、去重机制、缓存机制、输出格式模板、订阅功能、创作趋势分析逻辑。
注意事项:
- API 接口使用相同端点
https://redfox.hk/story/api/parseWork/queryPlayletMsgs - 必须设置
platform: 0才能获取公众号数据 - 公众号和抖音使用不同的缓存文件,互不干扰
❓ 常见问答
安装相关
Q1: API Key 怎么获取?
A: 前往 红狐Hub 官网 注册,登录后在个人中心获取,格式为 ak_xxxxxxxx。新注册用户获赠免费积分。
Q2: 配置了 API Key 但提示无效?
A: 请检查:
- Key 是否已正确复制(前后无空格)
- Windows 下需重启终端使环境变量生效
- 确认 Key 格式为
ak_开头
使用相关
Q3: 为什么查询今天的数据提示无数据?
A: 数据每日 15:00 更新前一天数据(实际可能延迟,以脚本真实探活为准)。脚本会自动向前回退获取最近时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动获取最近时间范围数据",无需手动处理。
Q4: 可以查询哪些题材?
A: 脚本内置 9 大题材分类:穿越、霸总、重生、悬疑、甜宠、逆袭、年代、战神、古装。你也可以通过 --topics 传入任意自定义关键词,但查询前会先校验关键词是否符合短剧题材词库,不满足时提醒+推荐相关词,不请求接口,避免浪费API额度。
Q5: 默认查询和自定义题材查询有什么区别?
A: 默认查询全部短剧内容(pageSize=200),数据不足时提示推荐题材并询问用户,确认后才扩展查询;自定义查询仅使用你提供的题材列表,无匹配数据时不自动查询,询问用户是否按推荐词重查。
故障排除
Q6: 脚本报错 UnicodeEncodeError 怎么办?
A: Windows 下需设置环境变量 PYTHONIOENCODING=utf-8,可在命令前加上 $env:PYTHONIOENCODING='utf-8';。
Q7: 接口返回错误码?
A: 常见错误码对照:
| 错误码 | 含义 | 解决方式 |
|---|---|---|
| 1002 | 每页条数超过 200 | 脚本自动限制,无需处理 |
| 3106 | 缺少 API Key | 配置 REDFOX_API_KEY 环境变量 |
| 3107 | API Key 无效 | 检查 Key 格式和有效性 |
| 3108 | 请求过于频繁 | 等待后重试 |
| 3109 | 今日调用达上限 | 次日再试 |
| 3201 | 积分不足 | 前往红狐Hub 充值 |
获取帮助
如有其他问题,可查看参考文档:
- core_workflow.md — 核心执行流程、日期预检、输出格式模板、错误处理
- examples.md — 使用示例与常见用法组合
📋 真实输出示例(2026-06-15)
以下为完整日报输出的真实样例,供 Agent 参考输出深度与格式规范。
短剧-公众号信息源 · 2026-06-15 日报
扫描 176 篇热门短剧文章,聚类 6 个题材方向
题材概览
| 题材 | 数量 | 占比 | 爆款亮点 |
|---|---|---|---|
| #其他 | 156篇 | 88.6% | 《价值升维,短剧与明星双向奔赴的2.0时代》2.3w阅读,AI短剧工具类内容大量涌现 |
| #甜宠 | 7篇 | 4.0% | 《热植物语》温馨睡前故事,均阅读800+,受众稳定 |
| #霸总 | 6篇 | 3.4% | 克拉拉转型短剧演员引热议,单篇最高4905阅读 |
| #悬疑 | 3篇 | 1.7% | 《短剧男演员去世真相》3801阅读,八卦向内容互动强 |
| #穿越 | 3篇 | 1.7% | 陕西短剧基地千万实景遇冷,产业观察类内容受关注 |
| #古装 | 1篇 | 0.6% | 《古装发型提示词,附图》1058阅读,AI创作辅助类单篇爆发 |
创作趋势分析
一、新兴起量信号
- 🔥 #古装 — 仅1篇但点赞率达3.6%(38赞/1058阅读),AI辅助创作类工具内容互动远超均值,提示词/工作流类内容有持续爆发潜力
- 🔥 #悬疑 — 仅3篇但头部阅读达3801,八卦揭秘+短剧圈内幕的组合标题互动效率高于大盘均值
二、爆款标题特征
| 特征模式 | 出现次数 | 典型案例 | 平均阅读 |
|---|---|---|---|
| 感叹号情绪钩子(!) | 93次 | 《OiiOii 2.0重磅升级,短剧带货真的要杀疯了...》 | 1374 |
| 疑问号悬念钩子(?) | 55次 | 《长短剧边界消融,演员在千亿短剧新局有何机遇?》 | 1325 |
| "N部"清单推荐体 | 13次 | 《5部高分上头短剧合集!霸总甜宠、都市治愈》 | 1072 |
| AI+工具/平台名 | 15次 | 《全网7亿播放的AI短剧,背后的神级制作工具我找到了!》 | 约6500 |
三、核心公众号榜
暂无核心公众号数据(本日接口未返回 accountName 字段)
四、题材趋势报告
题材:#甜宠 作品数:7篇 平均阅读:约900 头部作品:《热植物语》迪克羊仔(温馨甜宠睡前故事)— 1258阅读
题材特征:甜宠题材以"睡前故事""情头""宝藏剧推荐"为主要内容形态,标题普遍带有"甜""治愈""圆满"等情绪关键词,受众黏性高但流量天花板较低,阅读规模整体偏中腰部。 创作建议:可结合"CP向"二创内容、"甜宠+其他题材"复合标签(如甜宠×古装、甜宠×穿越)破圈,标题加入"闭眼追""宝藏""结局超甜"等完结承诺类钩子提升点击。
五、#霸总
题材:#霸总 作品数:6篇 平均阅读:约2911 头部作品:《"亚洲第一美女"克拉拉,被豪门抛弃,转型当短剧演员!》— 4905阅读
题材特征:霸总题材本日热度主要由"明星入局短剧"的八卦新闻驱动,而非传统霸总剧情推荐。"豪门""转型""被抛弃"等反差词构成核心流量钩子,汉南拍摄地话题也带动了在地化传播。 创作建议:可借势明星/演员话题切入霸总题材,标题结构采用"身份反差+转折"公式(如"被XX抛弃,转型XX"),同时结合"高分合集""上头短剧"清单体做长尾流量。
六、#悬疑
题材:#悬疑 作品数:3篇 平均阅读:约2047 头部作品:《短剧男演员去世真相,安以轩复出,侯明昊被拉出试水…》— 3801阅读
题材特征:悬疑题材本日以"圈内八卦+真相揭秘"形式呈现,标题普遍采用多个明星名串联+悬念问号的钩子结构;另有银发反诈AI微短剧(1718阅读)等政策向内容,整体数量少但单篇互动高于大盘均值。 创作建议:悬疑题材公众号端更适合"内幕揭秘""真相还原"等非虚构方向,标题可堆叠多个名人/事件名制造信息密度感,同时关注"反诈""社会议题"等政策风口,容易获得平台流量加持。
七、跨题材对比建议
- #霸总 × #甜宠 — 建议同步关注"霸总甜宠"复合标签的联动创作,本日《5部高分上头短剧合集!霸总甜宠、都市治愈》(2606阅读)已验证融合题材的合集形式有效,可进一步拆解两题材受众重叠度
- #AI短剧(其他类内隐主题)× 全题材 — 本日38篇AI短剧相关内容均阅读2630,远超大盘1994均值,AI工具+任意题材的"制作教程/工具测评"方向是当前显著流量洼地,建议各题材创作者关注AI制作工作流内容
日报地址:C:\Users\马祯\Downloads\QoderReports\短剧公众号日报_2026-06-15.html
数据说明:每日15:00更新昨天的数据
Files (redfox-community)
-
assets
-
daily_report.py 32.8 KB
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 短剧-公众号信息源日报生成脚本 (增强版 v2.3) ========================================== 每日扫描公众号短剧爆款内容,智能聚类题材后生成HTML日报 v2.3 调整说明(确认制:无数据不自动查询): - 【无数据确认制】查询无匹配数据 / 全量数据不足时,**禁止自动发起任何额外查询** (禁止自动降级全量、禁止自动扩展题材)。脚本停止并输出推荐题材关键词, 由 Agent 询问用户是否按推荐词重新查询,得到用户确认后才可发起查询。 - 全量查询数据不足(小于 AUTO_EXPAND_THRESHOLD)时仅提示推荐题材并等待确认, 已获取的数据仍正常生成日报。 v2.3.1 调整说明(相关词命中直查): - 【相关词命中直查】关键词校验匹配 topic_keywords 中规定的**题材名+全部相关词** (如「打脸」命中逆袭题材相关词、「总裁」命中霸总题材相关词、「宠妻/替身」命中 霸总相关词等),命中后**直接使用该关键词查询数据**(不替换题材、不降级全量)。 v2.2 调整说明(同步自"短剧-B站信息源" v2.2 增强 + 用户新规则): - 【前置校验】查询前先判断用户的输入条件: 1) 分类/关键词是否符合短剧题材词库(穿越/霸总/重生/甜宠/悬疑等) 2) 日期是否在有效查询范围(格式正确、不晚于今天) - 【不满足不请求接口】关键词/分类不满足短剧题材词库时,明确提醒"关键词不满足 查询条件"并推荐相关分类和关键词,**不发起任何接口请求**(避免浪费API额度), 直接停止并引导用户改用推荐词重新查询。 - 【日期兜底】用户查询的日期未更新或超过查询时间范围时,自动向前回退获取最近 时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动 获取最近时间范围数据"。 v2.0 增强说明(同步自B站版,针对"数据查询结果为空"问题的降失败率机制): 1. 【P0-日期探活】查询前先用 pageSize=1、不带 keyword 的轻量请求探测目标日期 是否有数据;无数据立即拦截,避免盲目消耗多题材查询额度。 2. 【P0-自动回退】--latest 从最近日期向前最多回退 FALLBACK_DAYS(默认7) 天, 找到第一个有数据的日期再生成日报;输出中明确标注实际数据日期。 3. 【确认制-扩展题材】全量查询数据不足(小于 AUTO_EXPAND_THRESHOLD)时, 不再自动扩展题材;提示 穿越→霸总→重生→悬疑→甜宠→逆袭 推荐顺序, 由 Agent 询问用户确认后才按 --topics 重新查询。 4. 【P1-空结果重试】单题材查询为空/异常时,间隔 RETRY_INTERVAL 秒重试 1 次。 5. 【P1-题材词校验】--topics 传入明显非题材词时给出提示(不阻断,仅提醒)。 6. 【P2-结构化空因】每次空结果输出原因分类:无数据 / 关键词无匹配 / API异常。 7. 【P2-防御式解析】兼容 {"code":2000,"data":{"list":[...]}} 与直出 list 两种 格式,防止服务端调整响应结构时脚本静默失效。 公众号平台适配(相对抖音版): - platform=0(公众号) - 排序与展示以阅读量 readCount 为核心指标 - 账号字段多字段兜底 verifyName / accountName / author - 文章链接多字段兜底 url / workUrl / articleUrl - 主题色 #07C160(微信绿) 用法与原版完全兼容: python3 playlet_wechat_daily.py --latest python3 playlet_wechat_daily.py --date 2026-08-05 python3 playlet_wechat_daily.py --topics "穿越,霸总" --latest """ import argparse import json import os import sys import time import webbrowser from datetime import datetime, timedelta from urllib import request, error # ============ 配置 ============ API_BASE_URL = "https://redfox.hk/story/api/parseWork/queryPlayletMsgs" CACHE_DIR = os.path.expanduser("~/.workbuddy/cache") CACHE_FILE = os.path.join(CACHE_DIR, "playlet_wechat_data.json") OUTPUT_DIR = os.path.expanduser("~/Downloads/QoderReports") DATA_UPDATE_HOUR = 15 # 数据源声称的更新时刻(仅作提示参考,不再作为唯一依据) FALLBACK_DAYS = 7 # --latest 自动回退的最大天数 RETRY_TIMES = 1 # 空结果/异常重试次数 RETRY_INTERVAL = 4 # 重试间隔(秒) REQUEST_TIMEOUT = 30 # 单次请求超时(秒) AUTO_EXPAND_THRESHOLD = 100 # 全量结果少于该值时提示用户确认是否扩展题材(不自动扩展) AUTO_EXPAND_TOPICS = ["穿越", "霸总", "重生", "悬疑", "甜宠", "逆袭"] # 推荐扩展顺序(仅供提示,需用户确认后才查询) HOT_TOPICS = ["穿越", "霸总", "重生", "悬疑", "甜宠", "逆袭", "年代", "战神", "古装"] # 推荐题材顺序 # 短剧题材词库:用于 --topics 输入校验提示 # 规则:关键词需命中 topic_keywords 中规定的题材名+全部相关词(如「打脸」命中逆袭题材相关词),命中后直接用该关键词查询数据 TOPIC_KEYWORDS_THESAURUS = { "穿越": ["穿越", "时空", "古代", "现代", "回到", "大宋", "北宋", "南宋", "唐朝", "明朝", "清朝"], "霸总": ["霸总", "总裁", "豪门", "冷酷", "宠妻", "娇妻", "替身"], "重生": ["重生", "逆袭", "回到", "翻盘", "重来", "再生"], "悬疑": ["悬疑", "推理", "反转", "惊悚", "谜案", "秘密", "真相"], "甜宠": ["甜宠", "恋爱", "撒糖", "甜蜜", "宠溺", "甜甜"], "逆袭": ["逆袭", "翻身", "打脸", "崛起", "反击", "报复"], "年代": ["年代", "八零", "九零", "七零", "六零"], "战神": ["战神", "龙王", "兵王", "高手"], "古装": ["古装", "宫廷", "皇后", "贵妃", "王爷", "世子"], } # 全部有效词集合(题材名 + 各题材相关词 + 扩展词),用于关键词前置校验 TOPIC_THESAURUS = { "穿越", "霸总", "重生", "悬疑", "甜宠", "逆袭", "年代", "战神", "古装", "总裁", "豪门", "复仇", "惊悚", "推理", "反转", "爽文", "科幻", "玄幻", "修仙", "都市", "职场", "萌宝", "萌娃", "亲子", "离婚", "闪婚", "替身", "虐恋", "先婚后爱", "双重生", } for _t, _kws in TOPIC_KEYWORDS_THESAURUS.items(): TOPIC_THESAURUS.add(_t) TOPIC_THESAURUS.update(_kws) # ============ 工具函数 ============ def get_api_key(): """从环境变量获取 API Key""" api_key = os.environ.get("REDFOX_API_KEY") if not api_key: print("❌ 错误:未找到 REDFOX_API_KEY 环境变量") print("请先配置:export REDFOX_API_KEY=<你的apikey>") sys.exit(1) return api_key def calculate_latest_date(): """按15:00规则估算最新可用日期(仅作初始起点,实际以探活为准)""" now = datetime.now() if now.hour < DATA_UPDATE_HOUR: return (now - timedelta(days=2)).strftime("%Y-%m-%d") else: return (now - timedelta(days=1)).strftime("%Y-%m-%d") def validate_date(date_str): """旧接口保留:基于本地时钟的日期校验(新逻辑改走 probe_date)""" latest_date = calculate_latest_date() target_date = datetime.strptime(date_str, "%Y-%m-%d") latest = datetime.strptime(latest_date, "%Y-%m-%d") return target_date <= latest, latest_date def check_topics(topics): """ v2.2 前置校验:判断用户输入的分类/关键词是否符合短剧题材词库。 返回 (有效词列表, 无效词列表, 推荐词列表) 推荐逻辑:优先从无效词中提取包含的题材词,再补充热门题材词。 """ hot_topics = ["穿越", "霸总", "重生", "甜宠", "悬疑", "逆袭", "年代", "战神", "古装", "都市", "科幻"] valid, invalid = [], [] for t in topics: if t in TOPIC_THESAURUS or t == "短剧": valid.append(t) else: invalid.append(t) recommends = [] for t in invalid: # 无效词若包含题材词(如"穿越重生"含"穿越""重生"),优先推荐 contained = [w for w in TOPIC_THESAURUS if w in t or t in w] for c in contained: if c not in recommends: recommends.append(c) for h in hot_topics: if h not in recommends: recommends.append(h) return valid, invalid, recommends def check_date(date_str): """ v2.2 前置校验:判断日期是否在有效查询范围(格式正确、不晚于今天)。 返回 (是否有效, 提示信息, 推荐日期或None) """ try: d = datetime.strptime(date_str, "%Y-%m-%d") except ValueError: return False, f"日期格式无效:{date_str}(应为 YYYY-MM-DD)", None today = datetime.now().date() if d.date() > today: latest = calculate_latest_date() return False, f"日期 {date_str} 超出有效查询范围(晚于今天,数据每日15:00更新前一天)", latest return True, "", None def parse_response(result): """ 防御式响应解析(加固,非修复):兼容两种格式 格式A(API实际完整响应): {"code":2000,"data":{"list":[...],"total":M},"msg":"..."} 格式B(兜底/直出): {"list":[...], "pageNum":1, "pages":N, "total":M} 返回: (items列表, error_msg或None) """ if not isinstance(result, dict): return [], "响应非JSON对象" # 格式A:code/data 包装(当前 API 实际格式) if result.get("code") == 2000: data = result.get("data") or {} return data.get("list") or [], None # 显式业务错误 code = result.get("code") if code is not None: msg = result.get("msg") return [], f"API业务错误 code={code} msg={msg}" # 格式B:直出 list(兜底) if "list" in result: return result.get("list") or [], None return [], None def http_post(payload, api_key): """执行一次 POST 请求,返回原始响应 dict(网络/HTTP 层异常向上抛)""" data = json.dumps(payload).encode('utf-8') req = request.Request( API_BASE_URL, data=data, headers={ "Content-Type": "application/json", "X-API-KEY": api_key }, method="POST" ) with request.urlopen(req, timeout=REQUEST_TIMEOUT) as response: return json.loads(response.read().decode('utf-8')) def build_payload(start_time, end_time, keyword=None, page_size=200): """构建请求体;keyword 为 None 时表示全量查询(不带 keyword 字段)""" payload = { "msgType": "短剧", "platform": 0, # 0=公众号 "source": "短剧公众号信息源-GitHub", "pageNum": 1, "pageSize": page_size, "startTime": start_time, "endTime": end_time, } if keyword: payload["keyword"] = keyword return payload def probe_date_available(api_key, start_time, end_time): """ 探活:pageSize=1 + 不带 keyword 的轻量请求,确认该日期是否有数据。 返回 (bool, info_str);False 说明该日期数据源无任何数据(未更新/缺失)。 成本:每次探测约 1 次接口额度,远低于无脑全量查询。 """ payload = build_payload(start_time, end_time, keyword=None, page_size=1) try: result = http_post(payload, api_key) items, err = parse_response(result) if err: print(f" ⚠️ 探活请求异常: {err}") return False, "probe_error" if items: return True, "ok" return False, "no_data" except Exception as e: print(f" ⚠️ 探活请求失败: {e}") return False, "probe_fail" def _fetch_topic_once(api_key, payload, topic): """单题材单次查询(含重试),返回 (items, api_error: bool)""" for attempt in range(RETRY_TIMES + 1): try: result = http_post(payload, api_key) items, err = parse_response(result) if err: if attempt < RETRY_TIMES: time.sleep(RETRY_INTERVAL) continue return items, False # 解析成功(可能为空 list,但非异常) except Exception as e: if attempt < RETRY_TIMES: print(f" ⚠️ 题材 {topic} 第{attempt+1}次请求失败({e}),{RETRY_INTERVAL}s后重试...") time.sleep(RETRY_INTERVAL) else: print(f"❌ 查询题材 {topic} 失败:{str(e)}") return [], True # ============ 数据获取 ============ def fetch_playlet_data( topics=None, start_time=None, end_time=None, count=200, use_cache=False, ): """ 调用 API 查询公众号短剧数据(增强版) Args: topics: 题材列表(逗号分隔),None/空 → 全量查询;数据不足时不自动扩展,提示用户确认 start_time / end_time: 查询时间窗 count: 扫描作品数量 use_cache: 是否使用缓存 Returns: (items, meta) 其中 meta 含 reason 字段用于结构化空因: reason in {"ok", "no_data", "probe_fail", "probe_error", "keyword_no_match", "api_error"} """ if use_cache: cached_data = load_cache() if cached_data: print("📦 使用缓存数据") return cached_data, {"reason": "ok", "note": "cache"} if not start_time or not end_time: latest_date = calculate_latest_date() start_time = f"{latest_date} 00:00:00" end_time = f"{latest_date} 23:59:59" api_key = get_api_key() meta = {"reason": "ok", "probed": False, "date": start_time[:10]} # ---- P0-2 探活:先确认该日期数据源是否有数据 ---- available, info = probe_date_available(api_key, start_time, end_time) meta["probed"] = True if not available: meta["reason"] = "no_data" if info == "no_data" else info print(f"📭 日期 {start_time[:10]} 数据源无数据({info}),跳过查询以避免浪费额度") return [], meta # ---- 确定查询题材序列 ---- # 用户指定题材 → 仅用用户列表(确认制:无匹配时不再自动降级/扩展) # 未指定 → 全量查询;数据不足时提示推荐题材并等待用户确认,不自动扩展 if topics: query_topics = list(topics) auto_expand = False else: query_topics = [None] auto_expand = True all_items = [] api_errors = 0 for topic in query_topics: keyword = None if topic is None or topic == "短剧" else topic payload = build_payload(start_time, end_time, keyword=keyword, page_size=min(count, 200)) items, had_error = _fetch_topic_once(api_key, payload, topic or "全量") if had_error: api_errors += 1 if items: all_items.extend(items) # ---- 确认制(v2.3):全量数据不足时不再自动扩展题材 ---- # 仅提示推荐题材并等待用户确认,确认前不发起任何额外请求 if auto_expand: unique_ids = {it.get("photoId") for it in all_items if it.get("photoId")} if len(unique_ids) < min(count, AUTO_EXPAND_THRESHOLD): print(f" ⚠️ 全量数据不足({len(unique_ids)}条 < {AUTO_EXPAND_THRESHOLD}),不自动扩展题材") print(f" 💡 推荐题材: {'、'.join(AUTO_EXPAND_TOPICS)}") print(f" ❓ 请确认是否按推荐题材扩展查询(使用 --topics 重新查询),确认前不会发起任何额外请求") meta["reason"] = "need_confirm_expand" # 去重(基于photoId) seen = set() unique_items = [] for item in all_items: item_id = item.get("photoId") if item_id and item_id not in seen: seen.add(item_id) unique_items.append(item) # 按阅读量排序(公众号核心指标是阅读量而非点赞量) unique_items.sort(key=lambda x: x.get("readCount", 0), reverse=True) if not unique_items: # 探活通过但实际查询为空 → 大概率是关键词无匹配 if topics and topics != [None]: meta["reason"] = "keyword_no_match" else: meta["reason"] = "no_data" return [], meta # 保存缓存 save_cache(unique_items) meta["reason"] = "ok" return unique_items[:count], meta # ============ 题材聚类 ============ def cluster_by_topic(items): """按题材聚类文章(词库与 TOPIC_KEYWORDS_THESAURUS 保持一致)""" topic_keywords = dict(TOPIC_KEYWORDS_THESAURUS) clusters = {} for item in items: title = item.get("title", "") matched_topics = [] for topic, keywords in topic_keywords.items(): if any(kw in title for kw in keywords): matched_topics.append(topic) matched_topic = matched_topics[0] if matched_topics else "其他" clusters.setdefault(matched_topic, []).append(item) return clusters # ============ HTML 日报 ============ def format_number(num): """格式化数字(万→w)""" if num is None: return "0" if num >= 10000: return f"{num/10000:.1f}w" return str(num) def generate_html_report(items, clusters, date_str): """生成HTML日报(微信绿 #07C160,阅读/点赞/评论零值隐藏)""" os.makedirs(OUTPUT_DIR, exist_ok=True) html_file = os.path.join(OUTPUT_DIR, f"短剧公众号日报_{date_str}.html") try: dt_obj = datetime.strptime(date_str, "%Y-%m-%d") weekdays = ["一", "二", "三", "四", "五", "六", "日"] date_cn = f"{dt_obj.year}年{dt_obj.month}月{dt_obj.day}日 星期{weekdays[dt_obj.weekday()]}" except ValueError: date_cn = date_str total_count = len(items) topic_count = len(clusters) total_reads = sum(item.get("readCount", 0) for item in items) avg_reads = total_reads / total_count if total_count > 0 else 0 category_cards = "" for i, (topic, topic_items) in enumerate( sorted(clusters.items(), key=lambda x: len(x[1]), reverse=True), 1): articles_html = "" for item in topic_items[:5]: title = item.get("title", "无标题") author = item.get("verifyName", "") or item.get("accountName", "") or item.get("author", "") # 公众号字段,多字段兜底 cover = item.get("coverUrl") or "" raw_reads = item.get("readCount") or 0 raw_likes = item.get("likeCount") or 0 raw_comments = item.get("commentCount") or 0 reads = format_number(raw_reads) # 阅读量 likes = format_number(raw_likes) # 点赞数 comments = format_number(raw_comments) # 评论数 url = item.get("url", "") or item.get("workUrl", "") or item.get("articleUrl", "") # 文章链接,多字段兜底 cover_html = "" if cover: cover_html = f'<img class="article-cover" src="{cover}" alt="" loading="lazy">' # 文章标题改为可点击链接 if url: title_html = f'<a class="article-title" href="{url}" target="_blank" rel="noopener noreferrer">{title}</a>' else: title_html = f'<span class="article-title">{title}</span>' # 各项数据为0时不展示该字段 metrics_parts = [] if raw_reads > 0: metrics_parts.append(f'<span class="metric">👁 {reads}</span>') if raw_likes > 0: metrics_parts.append(f'<span class="metric">👍 {likes}</span>') if raw_comments > 0: metrics_parts.append(f'<span class="metric">💬 {comments}</span>') metrics_html = "\n ".join(metrics_parts) if metrics_parts else "" articles_html += f''' <div class="article-item"> {cover_html} <div class="article-info"> {title_html} <div class="article-meta"> <span class="author">{author}</span> <span class="metrics"> {metrics_html} </span> </div> </div> </div>''' category_cards += f''' <div class="category-card reveal"> <div class="card-header"> <span class="card-number">{i:02d}</span> <h3 class="card-category">#{topic}</h3> <span class="card-count">{len(topic_items)} 篇</span> </div> <div class="card-body">{articles_html} </div> </div>''' timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") html_content = f'''<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>短剧-公众号信息源 - {date_str}</title> <style> * {{ margin: 0; padding: 0; box-sizing: border-box; }} body {{ font-family: -apple-system, sans-serif; background: #1a1a1a; color: #e8e4df; padding: 2rem; }} .header {{ text-align: center; padding: 2rem 0; }} .header h1 {{ font-size: 2rem; color: #07C160; }} .header p {{ color: #9a9590; margin-top: 0.5rem; }} .stats {{ display: flex; justify-content: center; gap: 2rem; padding: 1rem; margin: 1rem 0; }} .stat-item {{ text-align: center; }} .stat-value {{ font-size: 1.5rem; font-weight: bold; color: #07C160; }} .stat-label {{ font-size: 0.8rem; color: #9a9590; }} .cards {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 1.5rem; max-width: 1200px; margin: 2rem auto; }} .category-card {{ background: #2d2d2d; border-radius: 12px; padding: 1.5rem; }} .card-header {{ display: flex; align-items: center; gap: 0.8rem; margin-bottom: 1rem; padding-bottom: 0.8rem; border-bottom: 1px solid #3d3d3d; }} .card-number {{ font-size: 1.5rem; font-weight: bold; color: #07C160; }} .card-category {{ flex: 1; font-size: 1.1rem; }} .card-count {{ color: #9a9590; font-size: 0.9rem; }} .article-item {{ padding: 0.6rem 0; border-bottom: 1px solid #3d3d3d; display: flex; gap: 0.8rem; }} .article-item:last-child {{ border-bottom: none; }} .article-cover {{ width: 60px; height: 60px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }} .article-info {{ flex: 1; min-width: 0; }} .article-title {{ color: #e8e4df; font-size: 0.9rem; line-height: 1.4; display: block; text-decoration: none; transition: color 0.2s; }} .article-title:hover {{ color: #07C160; }} .article-meta {{ display: flex; justify-content: space-between; margin-top: 0.3rem; font-size: 0.75rem; color: #9a9590; }} .metrics {{ display: flex; gap: 0.8rem; }} .footer {{ text-align: center; padding: 2rem; color: #666; font-size: 0.8rem; }} .reveal {{ animation: fadeIn 0.5s ease-in; }} @keyframes fadeIn {{ from {{ opacity: 0; transform: translateY(20px); }} to {{ opacity: 1; transform: translateY(0); }} }} </style> </head> <body> <div class="header"> <h1>📱 短剧-公众号信息源</h1> <p>{date_cn} | 共 {total_count} 篇热门短剧文章</p> </div> <div class="stats"> <div class="stat-item"><div class="stat-value">{topic_count}</div><div class="stat-label">题材</div></div> <div class="stat-item"><div class="stat-value">{total_count}</div><div class="stat-label">文章</div></div> <div class="stat-item"><div class="stat-value">{format_number(int(avg_reads))}</div><div class="stat-label">平均阅读</div></div> <div class="stat-item"><div class="stat-value">{format_number(total_reads)}</div><div class="stat-label">总阅读</div></div> </div> <div class="cards">{category_cards}</div> <div class="footer">Generated at {timestamp} by 短剧-公众号信息源 Skill<br>数据说明:每日15:00更新前一天的数据 | 数据来源:红狐Hub</div> </body> </html>''' with open(html_file, 'w', encoding='utf-8') as f: f.write(html_content) return html_file # ============ 缓存 ============ def load_cache(): if not os.path.exists(CACHE_FILE): return None try: with open(CACHE_FILE, 'r', encoding='utf-8') as f: cache_data = json.load(f) if time.time() - cache_data.get("timestamp", 0) < 3600: return cache_data.get("items") except Exception: pass return None def save_cache(items): os.makedirs(CACHE_DIR, exist_ok=True) cache_data = {"timestamp": time.time(), "items": items} try: with open(CACHE_FILE, 'w', encoding='utf-8') as f: json.dump(cache_data, f, ensure_ascii=False, indent=2) except Exception: pass # ============ 主流程 ============ def find_latest_available_date(api_key, max_fallback=FALLBACK_DAYS): """ P0-2 自动回退:从最近日期开始向前探测,返回第一个有数据的日期。 返回 (date_str, found: bool) """ latest = calculate_latest_date() cursor = datetime.strptime(latest, "%Y-%m-%d") for i in range(max_fallback + 1): d = (cursor - timedelta(days=i)).strftime("%Y-%m-%d") print(f" 🔎 探测 {d} ...", end="") ok, info = probe_date_available( api_key, f"{d} 00:00:00", f"{d} 23:59:59" ) print(" 有数据" if ok else f" 无数据({info})") if ok: return d, True return latest, False def main(): global OUTPUT_DIR parser = argparse.ArgumentParser(description="短剧-公众号信息源日报生成工具 (v2.3确认制)") parser.add_argument("--topics", type=str, help="题材关键词,逗号分隔;不满足短剧题材词时提醒并推荐,不请求接口") parser.add_argument("--count", type=int, default=200, help="扫描文章数量") parser.add_argument("--date", type=str, help="指定日期 YYYY-MM-DD;超出有效范围时提醒并自动回退最近有数据的日期") parser.add_argument("--start-time", type=str, help="开始时间 YYYY-MM-DD HH:MM:SS") parser.add_argument("--end-time", type=str, help="结束时间 YYYY-MM-DD HH:MM:SS") parser.add_argument("--latest", action="store_true", help="使用最新有数据的日期(自动回退)") parser.add_argument("--output-dir", type=str, default=OUTPUT_DIR, help="输出目录") parser.add_argument("--api-key", type=str, help="指定 API Key") parser.add_argument("--subscribe", action="store_true", help="开启每日订阅") parser.add_argument("--unsubscribe", action="store_true", help="关闭每日订阅") parser.add_argument("--from-cache", action="store_true", help="使用缓存数据") args = parser.parse_args() if args.subscribe: print("✅ 已开启每日订阅,日报将自动保存至:", OUTPUT_DIR) return if args.unsubscribe: print("✅ 已关闭每日订阅") return if args.output_dir: OUTPUT_DIR = args.output_dir api_key = args.api_key or get_api_key() # ---- 前置校验:关键词/分类是否符合短剧题材词库(不满足则不请求接口)---- topics = None if args.topics: raw_topics = [t.strip() for t in args.topics.split(",") if t.strip()] valid_topics, invalid_topics, recommends = check_topics(raw_topics) if invalid_topics: print(f"⚠️ 关键词 {invalid_topics} 不满足短剧查询条件(短剧按题材/剧情词匹配标题,非短剧题材词大概率无结果)") print(f"💡 推荐相关分类和关键词:{'、'.join(recommends[:10])}") if valid_topics: print(f"✅ 已保留有效关键词 {valid_topics} 继续查询,无效关键词已自动忽略") topics = valid_topics else: print("🛑 关键词均不满足短剧查询条件,未发起任何接口请求。请使用推荐题材词重新查询。") return else: topics = valid_topics # ---- 确定查询日期 ---- if args.start_time: start_time = args.start_time date_str = args.start_time[:10] end_time = args.end_time or f"{date_str} 23:59:59" elif args.latest: # P0-2 自动回退:探测最近有数据的日期 print(f"🔎 --latest: 自动寻找最近有数据的日期(最多回退{FALLBACK_DAYS}天)...") date_str, found = find_latest_available_date(api_key) if not found: print(f"📭 最近 {FALLBACK_DAYS} 天内均无数据,请稍后再试或联系数据源确认更新状态") return start_time = f"{date_str} 00:00:00" end_time = f"{date_str} 23:59:59" print(f"✅ 已定位最新可用日期: {date_str}") elif args.date: date_str = args.date # v2.2: 前置校验——日期格式与有效查询范围 date_ok, date_msg, date_suggest = check_date(date_str) if not date_ok: print(f"⚠️ {date_msg}") if date_suggest: print(f"💡 推荐查询时间范围:{date_suggest}(已为您自动获取该时间范围数据)") # 探活式预检(替代纯本地时钟判断) ok, info = probe_date_available(api_key, f"{date_str} 00:00:00", f"{date_str} 23:59:59") if not ok: # v2.1: 日期兜底——未更新/超范围时自动回退最近有数据的日期,不再等待确认 print(f"⚠️ 当前查询时间 {date_str} 未更新或超过查询时间范围,已为您自动获取最近时间范围数据...") new_date, found = find_latest_available_date(api_key) if not found: print(f"📭 最近 {FALLBACK_DAYS} 天内均无数据,请稍后再试或联系数据源确认更新状态") return print(f"✅ 已为您自动获取最近时间范围数据: {new_date}(原查询 {date_str} 未更新或超过查询时间范围)") date_str = new_date start_time = f"{date_str} 00:00:00" end_time = f"{date_str} 23:59:59" else: date_str = calculate_latest_date() start_time = f"{date_str} 00:00:00" end_time = f"{date_str} 23:59:59" print(f"🔍 正在查询 {date_str} 的公众号短剧数据...") items, meta = fetch_playlet_data( topics=topics, start_time=start_time, end_time=end_time, count=args.count, use_cache=args.from_cache, ) if not items: reason = meta.get("reason", "unknown") hint = { "no_data": "数据源当日无数据(未更新或缺失)", "probe_fail": "探测请求失败(网络/接口异常)", "probe_error": "探测请求异常(接口返回异常)", "keyword_no_match": "查询条件(题材词)在该日期无匹配作品", "api_error": "接口调用异常", }.get(reason, "未知原因") print(f"📭 未查询到相关数据 [原因: {hint}]") if reason == "keyword_no_match": # v2.3 确认制:无匹配数据时展示推荐关键词,等待用户确认后才可查询,禁止自动查询 print("🛑 未发起任何额外查询(禁止自动降级全量 / 自动扩展题材)") print(f"💡 推荐题材:{'、'.join(AUTO_EXPAND_TOPICS)}、年代、战神、古装、都市") print(f"❓ 是否按推荐题材(如 {AUTO_EXPAND_TOPICS[0]}/{AUTO_EXPAND_TOPICS[1]})重新查询?" f"请确认后使用 --topics 重新查询。") elif reason == "no_data": print("💡 建议: 使用 --latest 自动回退到最近有数据的日期") return print(f"✅ 共获取 {len(items)} 篇短剧文章") if meta.get("reason") == "need_confirm_expand": # v2.3 确认制:全量数据不足时未自动扩展,提示推荐题材并等待用户确认 print(f"⚠️ 全量数据不足,未自动扩展题材(禁止自动查询)。推荐题材:{'、'.join(AUTO_EXPAND_TOPICS)}") print(f"❓ 是否按推荐题材扩展查询?请确认后使用 --topics 重新查询(确认前不发起额外请求)。") clusters = cluster_by_topic(items) print(f"📊 聚类为 {len(clusters)} 个题材方向") html_file = generate_html_report(items, clusters, date_str) print(f"📄 日报已生成:{html_file}") webbrowser.open(f"file://{html_file}") print(f"\n## 短剧-公众号信息源 · {date_str} 日报\n") print(f"**扫描 {len(items)} 篇热门短剧文章,聚类 {len(clusters)} 个题材方向**\n") print("### 题材概览\n") print("| 题材 | 数量 | 占比 | 爆款亮点 |") print("|------|------|------|---------|") for topic, topic_items in sorted(clusters.items(), key=lambda x: len(x[1]), reverse=True): top_item = topic_items[0] if topic_items else {} print(f"| #{topic} | {len(topic_items)}篇 | {len(topic_items)/len(items)*100:.1f}% | 《{top_item.get('title', '')[:20]}》{format_number(top_item.get('readCount', 0))}阅读 |") if __name__ == "__main__": main()
-
-
references
-
core_workflow.md 15.1 KB
# 短剧-公众号信息源 - 核心工作流程 ## 执行流程总览 1. **第零步**:输入与日期预检(必须执行,先于任何接口调用) 2. **第一步**:生成爆款日报(调用脚本) 3. **第二步**:执行创作趋势分析(基于脚本输出) --- ## 第零步:输入与日期预检(必须执行,先于任何接口调用) > ⛔ **核心规则:关键词/分类不满足短剧题材词库时,不发起任何接口请求** **数据更新规则**:每日15:00更新前一天的数据(实际可能延迟,以脚本真实探活为准) - 15:00前:估算最新可用日期 = T-2(前天)——仅作初始起点 - 15:00后:估算最新可用日期 = T-1(昨天)——仅作初始起点 **执行流程(每次查询前强制执行)**: 1. **关键词/分类前置校验**:判断用户输入的分类/关键词是否命中短剧题材词库(`topic_keywords` 中规定的**题材名+全部相关词**,如「打脸」命中逆袭题材相关词、「总裁」命中霸总题材相关词;**命中后直接使用该关键词查询数据**) - 不满足时提醒"关键词不满足查询条件",推荐相关分类和关键词,**不发起接口请求**,直接停止并引导用户改用推荐词 - 混合词场景:保留有效关键词继续查询,无效关键词自动忽略并提示 - 全部无效:**不请求接口**,停止并推荐相关词 2. **日期前置校验**:判断目标日期格式是否有效、是否晚于今天;超出范围时提醒并推荐最近可用日期 3. **真实探活**:用 `pageSize=1` 不带 keyword 的轻量请求**实际探测**目标日期是否有数据,以接口返回为准(替代纯本地时钟推断) 4. **日期兜底**:目标日期未更新或超过查询时间范围时,自动向前回退获取最近时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动获取最近时间范围数据",无需用户确认 5. `--latest` 模式同样自动向前回退(最多7天)定位最近有数据的日期 6. **无数据确认制(v2.3)**:题材关键词查询无匹配数据 / 全量数据不足(<100条)时,**禁止自动发起任何额外查询**(禁止自动降级全量、禁止自动扩展题材),必须向用户展示推荐题材关键词并询问"是否按推荐题材重新查询",得到用户确认后才可发起查询 7. 若回退 7 天内均无数据,提示用户稍后再试或联系数据源确认更新状态 **示例对话**: ``` 用户:查询今天的短剧公众号日报 Agent:(执行 --latest,脚本自动向前回退定位最近有数据的日期,直接生成日报) 用户:查询"智能辅助驾驶"题材的短剧文章 Agent:⚠️ 关键词 ['智能辅助驾驶'] 不满足短剧查询条件(短剧按题材/剧情词匹配标题,非短剧题材词大概率无结果) 💡 推荐相关分类和关键词:穿越、霸总、重生、甜宠、悬疑、逆袭、年代、战神、古装、都市 🛑 关键词均不满足短剧查询条件,未发起任何接口请求。请使用推荐题材词重新查询。 用户:查询"打脸"题材的短剧文章 Agent:(关键词命中逆袭题材相关词 → 直接使用"打脸"查询数据) 用户:查询"古装"题材的短剧文章(该日期无匹配数据) Agent:📭 未查询到相关数据 [原因: 查询条件(题材词)在该日期无匹配作品] 🛑 未发起任何额外查询(禁止自动降级全量 / 自动扩展题材) 💡 推荐题材:穿越、霸总、重生、甜宠、悬疑、逆袭、年代、战神、古装、都市 ❓ 是否按推荐题材(如 穿越/霸总)重新查询?请确认后我再查询。 ``` ## 第一步:生成爆款日报 ```bash # 生成最新一期日报(--latest 自动向前回退最多7天定位最近有数据的日期,不扣积分) python3 "$SKILL_PATH/assets/daily_report.py" --latest # 生成指定日期日报(历史日期已有数据,无需确认) python3 "$SKILL_PATH/assets/daily_report.py" --date 2026-06-10 # 自定义题材查询(用户指定方向;无匹配/数据不足时不自动扩展,询问用户确认后重查) python3 "$SKILL_PATH/assets/daily_report.py" --topics "穿越,霸总,重生,悬疑" --latest # 订阅 / 取消订阅 python3 "$SKILL_PATH/assets/daily_report.py" --subscribe python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe ``` > **查询策略**:默认查询全部短剧内容(pageSize=200)。**无数据确认制(v2.3)**:数据不足(小于100条)时**不再自动扩展题材**,脚本提示推荐题材(穿越→霸总→重生→悬疑→甜宠→逆袭)并等待用户确认,确认后才通过 `--topics` 重新查询;用户自定义题材时仅使用用户提供的列表。**关键词校验规则(v2.3.1)**:关键词需命中短剧题材词库(`topic_keywords` 中规定的**题材名+全部相关词**),**命中后直接使用该关键词查询数据**;不满足时提醒+推荐,**不请求接口**。查询前自动探活目标日期;空结果自动重试1次。 > **日期智能判断**:脚本内置 `DATA_UPDATE_HOUR = 15` 常量(每日15:00更新前一天数据),查询前先用轻量请求(pageSize=1, 无keyword)真实探测目标日期是否有数据,替代纯本地时钟推断;目标日期未更新或超过查询范围时自动向前回退最多7天定位最近有数据的日期。 > **降失败率机制(v2.0增强)**: > - **真实探活**:查询前先用 `pageSize=1` 无 keyword 轻量请求探测目标日期,以接口返回为准(数据源实际更新可能晚于15:00),无数据立即拦截,避免空跑耗额度 > - **自动回退**:`--latest` 从最近日期向前最多回退7天,定位第一个有数据的日期再出日报 > - **空结果重试**:单题材查询为空/异常时自动重试1次(间隔4秒) > - **题材词校验**:`--topics` 传入非题材词时提示并推荐相关词,不满足时**不请求接口** > - **结构化空因**:空结果明确输出"无数据/关键词无匹配/接口异常"及下一步建议 ## 第二步:执行创作趋势分析 日报生成后,**必须**基于聚类结果自动执行创作趋势分析: 1. 读取题材聚类结果,选取TOP 5热门题材 2. 分析每个题材的爆款数量、平均互动数据、头部作品特征 3. 识别新兴起量题材(数量少但互动高) 4. 输出结构化创作趋势报告 生成的HTML日报保存在 `~/Downloads/QoderReports/`,自动浏览器打开。终端同步输出题材分类表格 + 创作趋势分析报告。 --- ## 输出格式(强制执行) > ⛔ **严格执行规则**: > - 以下模板是**唯一合法输出格式**,禁止任何自由发挥、省略、简化或重新组织 > - 禁止输出模板中未定义的额外内容(如"我来帮你…""以下是…"等口语化文字) > - 禁止合并、跳过任何板块,即使某板块数据为"暂无"也必须保留该板块标题 > - 日报生成后,对话回复**只能**包含以下内容,不得包含其他任何文字 每次运行日报后,对话输出**必须严格**按以下模板原样输出(仅替换 `{...}` 占位符): ``` ## 短剧-公众号信息源 · {日期} 日报 **扫描 {N} 篇热门短剧文章,聚类 {M} 个题材方向** --- ### 题材概览 | 题材 | 数量 | 占比 | 爆款亮点 | |------|------|------|---------| | #{题材名} | {N}篇 | {X}% | 《{头部作品标题}》{阅读数}阅读,{该题材当日内容特征简述} | | ... | ... | ... | ... | --- ### 创作趋势分析 **一、新兴起量信号** - 🔥 **#{题材}** — 仅{N}篇但{核心互动指标描述(如:均阅读X+、点赞率X%等)},{起量原因/内容特征分析} (若无新兴起量信号,输出:暂无新兴起量信号) > 新兴起量判断标准:作品数≤3篇但头部阅读超过大盘均值,或互动率(点赞/阅读)显著高于其他题材 **二、爆款标题特征** | 特征模式 | 出现次数 | 典型案例 | 平均阅读 | |---------|---------|---------|---------| | {标题结构特征描述(如:感叹号情绪钩子(!)、"N部"清单推荐体、AI+工具/平台名等)} | {N}次 | 《{标题}》 | {X} | | ... | ... | ... | ... | (若无标题数据,输出:暂无爆款标题数据) > 标题特征分析维度:标点符号使用(!/?/…)、数字清单体(N部/N条)、关键词类型(AI/明星/工具)、情绪钩子结构(反差词/悬念词/承诺词) **三、核心公众号榜** | 公众号 | 作品数 | 总阅读 | 代表作 | |--------|--------|--------|--------| | @{公众号} | {N}篇 | {X}w | 《{作品}》 | | ... | ... | ... | ... | (若无公众号数据,输出:暂无核心公众号数据(本日接口未返回 accountName 字段)) **四、题材趋势报告** **题材**:#{题材1} **作品数**:{N}篇 **平均阅读**:{X} **头部作品**:《{标题}》— {阅读}阅读 **题材特征**:{基于当日数据描述该题材的内容形态、标题特征、受众画像、流量天花板等} **创作建议**:{基于数据给出可执行的创作方向、标题公式、题材融合建议等} **五、#{题材2}** (同上格式) **六、#{题材3}** (同上格式) > 题材趋势报告选取 TOP 3 题材(排除"其他")逐一展开分析,每个题材必须包含「题材特征」和「创作建议」两个子模块 **七、跨题材对比建议** - **{题材A} × {题材B}** — {两题材的联动创作建议,基于当日数据中发现的跨题材信号} - **{主题线索(如:AI短剧)} × 全题材** — {当日数据中发现的跨题材共性趋势及创作机会} (若无建议,输出:暂无跨题材对比建议) --- **日报地址**:{HTML文件绝对路径} > 数据说明:每日15:00更新昨天的数据 ``` > 以上格式为**强制规范**,所有字段不可省略,板块标题(一、二、三、四、五、六、七)必须保留。若某模块无数据则在该板块内标注"暂无",不得删除板块本身。 **输出质量要求**: - 题材概览的「爆款亮点」必须包含该题材当日的内容特征简述,不能仅列出头部作品 - 爆款标题特征必须基于实际数据归纳,特征模式需具体可操作(如"感叹号情绪钩子"而非"情绪化标题") - 题材趋势报告的「题材特征」和「创作建议」必须基于当日数据,不能套用通用描述 - 跨题材对比建议必须从当日数据中发现真实联动信号,不能凭空推测 - HTML 日报中各项互动数据(阅读量 👁 / 点赞数 👍 / 评论数 💬)**为 0 时不展示该字段**,只展示有实际数据的指标 --- ## 输入解析 用户输入支持以下几种方式: | 输入方式 | 示例 | 解析参数 | |---------|------|---------| | 查询默认短剧日报 | "查询今天的短剧公众号日报" | `--latest` | | 按题材查询 | "穿越题材的短剧" | `topics="穿越"` | | 按时间查询 | "6月的短剧爆款" | `start_time="2026-06-01 00:00:00", end_time="2026-06-30 23:59:59"` | | 组合查询 | "穿越题材6月短剧" | `topics="穿越", start_time/end_time` | | 指定日期 | "6月10日的短剧日报" | `date="2026-06-10"` | ## 参数说明 | 参数 | 说明 | 默认值 | |------|------|--------| | `--topics` | 自定义题材关键词,逗号分隔。查询前先校验是否命中短剧题材词库(题材名+全部相关词,命中后直接使用该关键词查询),不满足时提醒+推荐相关词并**不请求接口**;无匹配数据时不自动查询(确认制),询问用户确认后才重查。默认查询全部短剧,数据不足时不自动扩展题材 | `短剧` | | `--count` | 扫描文章数量,满足即停 | `200` | | `--date` | 指定日期 YYYY-MM-DD(未更新或超范围时自动回退最近有数据的日期) | 今天 | | `--start-time` | 自定义开始时间 YYYY-MM-DD HH:MM:SS(覆盖 --date 推算) | — | | `--end-time` | 自定义结束时间 YYYY-MM-DD HH:MM:SS(覆盖 --date 推算) | — | | `--latest` | 自动向前回退最多7天,定位最近有数据的日期,跳过无数据区间,不扣积分 | — | | `--output-dir` | 输出目录 | `~/Downloads/QoderReports` | | `--api-key` | 指定 API Key | — | | `--subscribe` | 开启每日订阅 | — | | `--unsubscribe` | 关闭每日订阅 | — | | `--from-cache` | 使用缓存数据,避免重复调用接口 | — | ### topics(题材类型) 热门题材包括但不限于: | 题材 | 说明 | 典型关键词 | |------|------|-----------| | 穿越 | 穿越时空题材 | 穿越、时空、古代、现代 | | 霸总 | 霸道总裁题材 | 霸总、总裁、豪门 | | 重生 | 重生逆袭题材 | 重生、回到、逆袭 | | 悬疑 | 悬疑推理题材 | 悬疑、推理、反转、惊悚 | | 甜宠 | 甜蜜宠溺题材 | 甜宠、恋爱、撒糖 | | 逆袭 | 逆袭成长题材 | 逆袭、翻身、打脸 | #### 平台固定为公众号 本skill专注于公众号平台短剧内容,platform固定为 `0`(公众号)。 接口调用时通过 `source` 字段同步记录,值为 `短剧公众号信息源-GitHub`。 ## 日期处理逻辑 当用户提到时间时,自动转换为 `yyyy-MM-dd HH:mm:ss` 格式: | 用户输入 | 转换结果 | |---------|---------| | "今天" | `startTime=今日00:00:00, endTime=今日23:59:59` | | "昨天" | `startTime=昨日00:00:00, endTime=昨日23:59:59` | | "本周" | `startTime=周一00:00:00, endTime=周日23:59:59` | | "6月" | `startTime=2026-06-01 00:00:00, endTime=2026-06-30 23:59:59` | | "近7天" | `startTime=7天前, endTime=当前时间` | ## 题材聚类规则 脚本自动根据文章标题和标签进行题材聚类: 1. **关键词匹配**:根据题材关键词库匹配文章题材 2. **多标签处理**:一篇文章可能属于多个题材,按主题材归类 3. **未知题材**:无法识别的归类为"其他" 4. **动态调整**:每日题材分类由当日内容动态决定,不固化 ## 创作趋势分析逻辑 **新兴起量信号识别**: - 题材文章数 < 10 但平均阅读 > 5w - 或单篇文章阅读 > 20w **爆款标题特征提取**: - 统计高频词汇(前20个) - 识别标题模式(如"重生之XX"、"XX霸总"等) - 计算各模式的平均阅读数据 **核心公众号评选**: - 按文章数排序(≥3篇) - 同文章数按总阅读排序 - 展示TOP 10公众号 ## 公众号字段映射 与抖音版本相比,公众号版本的核心字段调整: | 抖音字段 | 公众号字段 | 说明 | |---------|-----------|------| | userName | accountName | 账号名称字段 | | likeCount | readCount (排序依据) | 公众号以阅读量为核心指标 | | 点赞量(主) | 阅读量(主) | 排序和展示的核心指标变更 | | platform: 1 | platform: 0 | 平台标识符变更 | | 短剧抖音日报 | 短剧公众号日报 | 输出文件命名 | ## 缓存机制 - 缓存路径:`~/.workbuddy/cache/playlet_wechat_data.json` - 缓存时间:1 小时 - 使用 `--from-cache` 参数可使用缓存数据 ## 常见错误处理 | 错误码 | 错误信息 | 处理方式 | |--------|---------|---------| | 1002 | 每页条数不能超过200 | 自动限制 page_size ≤ 200 | | 3106 | 缺少 API Key | 提示用户配置 REDFOX_API_KEY | | 3107 | API Key 无效 | 检查 Key 格式和有效性 | | 3108 | 请求过于频繁 | 等待后重试 | | 3109 | 今日调用次数达上限 | 提示用户次日再试 | | 3201 | 积分不足 | 提示用户充值积分 | -
examples.md 5 KB
# 短剧-公众号信息源 - 使用示例 ## 基础用法 ### 1. 查询今日短剧公众号日报 ```bash python3 "$SKILL_PATH/assets/daily_report.py" --latest ``` **使用场景**:用户想了解今天公众号上最火的短剧内容 **预期输出**: - HTML日报文件:`~/Downloads/QoderReports/短剧公众号日报_2026-06-17.html` - 终端输出题材分类表格 - 自动浏览器打开日报 --- ### 2. 查询指定日期 ```bash python3 "$SKILL_PATH/assets/daily_report.py" --date 2026-06-10 ``` **使用场景**:回顾某天的短剧爆款内容 **注意事项**: - 如果指定日期数据未更新,会提示并询问是否切换 - 历史日期已有数据无需确认 --- ### 3. 自定义题材查询 ```bash # 查询穿越题材 python3 "$SKILL_PATH/assets/daily_report.py" --topics "穿越,时空,重生" # 查询霸总/甜宠题材 python3 "$SKILL_PATH/assets/daily_report.py" --topics "霸总,甜宠,总裁,虐恋" # 查询悬疑/反转题材 python3 "$SKILL_PATH/assets/daily_report.py" --topics "悬疑,推理,反转,惊悚" ``` **使用场景**:用户关注特定题材方向的短剧内容 **查询逻辑**: - 所有题材通过批量接口一次性查询 - 结果自动去重 - 题材聚类基于查询结果生成 --- ### 4. 时间范围查询 ```bash # 查询6月短剧爆款 python3 "$SKILL_PATH/assets/daily_report.py" \ --start-time "2026-06-01 00:00:00" \ --end-time "2026-06-30 23:59:59" # 查询近7天短剧 python3 "$SKILL_PATH/assets/daily_report.py" \ --start-time "2026-06-10 00:00:00" \ --end-time "2026-06-17 23:59:59" ``` **使用场景**:分析一段时间内的短剧趋势 --- ### 5. 组合查询 ```bash # 查询穿越题材6月短剧 python3 "$SKILL_PATH/assets/daily_report.py" \ --topics "穿越" \ --start-time "2026-06-01 00:00:00" \ --end-time "2026-06-30 23:59:59" ``` **使用场景**:精准定位特定题材+时间范围的内容 --- ## 订阅功能 ### 开启每日订阅 ```bash python3 "$SKILL_PATH/assets/daily_report.py" --subscribe ``` **效果**: - 每日自动产出短剧公众号日报 - 日报自动保存至 `~/Downloads/QoderReports/` - 文件名格式:`短剧公众号日报_2026-06-17.html` ### 取消订阅 ```bash python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe ``` --- ## 高级用法 ### 使用缓存数据 ```bash python3 "$SKILL_PATH/assets/daily_report.py" --from-cache ``` **使用场景**:快速查看最近查询的结果,避免重复调用接口 **缓存说明**: - 缓存路径:`~/.workbuddy/cache/playlet_wechat_data.json` - 缓存时间:1小时 - 超过1小时自动失效 --- ### 指定API Key ```bash python3 "$SKILL_PATH/assets/daily_report.py" --api-key ak_your_key_here ``` **使用场景**:使用个人API Key而非环境变量 --- ### 扩大扫描范围 ```bash python3 "$SKILL_PATH/assets/daily_report.py" --count 300 ``` **使用场景**:想看到更多热门短剧文章 **默认值**:200篇 --- ## 常见对话示例 ### 场景1:查询今日日报 ``` 用户:查询今天的短剧公众号日报 Agent:(执行 --latest,脚本自动向前回退定位最近有数据的日期,直接生成日报) ``` > **说明**:若目标日期未更新或超过查询时间范围,脚本会自动向前回退获取最近时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动获取最近时间范围数据",无需用户确认。 --- ### 场景2:查询特定题材 ``` 用户:我想看穿越题材的短剧公众号文章 Agent:(执行脚本 --topics "穿越") 📊 共扫描 86 篇短剧文章,聚类 5 个题材方向 ... ``` --- ### 场景3:查询历史数据 ``` 用户:6月10号的短剧公众号日报有吗? Agent:(执行脚本 --date 2026-06-10) 📊 共扫描 152 篇短剧文章,聚类 7 个题材方向 ... ``` --- ### 场景4:时间范围分析 ``` 用户:这个月的短剧趋势怎么样? Agent:(执行脚本,计算本月时间范围) 📊 共扫描 456 篇短剧文章,聚类 9 个题材方向 ... ``` --- ## 输出格式说明 ### 终端输出 ``` ## 短剧-公众号信息源 · 2026-06-17 日报 **扫描 186 篇热门短剧文章,聚类 8 个题材方向** --- ### 题材概览 | 题材 | 数量 | 占比 | 爆款亮点 | |------|------|------|---------| | #重生 | 45篇 | 24.2% | 《重生之我在AI圈写短剧》32.8w阅读 | | #穿越 | 38篇 | 20.4% | 《穿越之霸总爱上我》21.5w阅读 | | ... | ... | ... | ... | ``` ### HTML日报 - 深色主题设计 - 题材卡片布局 - 每篇文章展示:封面图、标题、公众号名称、阅读量、点赞数、评论数 - 统计面板:题材数、文章数、平均阅读、总阅读 --- ## 注意事项 1. **日期规则**:每日15:00更新前一天数据,查询前必须先确认日期有效性 2. **API Key**:必须配置 `REDFOX_API_KEY` 环境变量或使用 `--api-key` 参数 3. **去重机制**:基于photoId自动去重,避免重复内容 4. **题材聚类**:每天题材分类由内容动态决定,不固化 5. **平台标识**:公众号platform=0,与抖音platform=1不同
-
-
scripts
-
playlet_wechat_daily.py 32.8 KB
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 短剧-公众号信息源日报生成脚本 (增强版 v2.3) ========================================== 每日扫描公众号短剧爆款内容,智能聚类题材后生成HTML日报 v2.3 调整说明(确认制:无数据不自动查询): - 【无数据确认制】查询无匹配数据 / 全量数据不足时,**禁止自动发起任何额外查询** (禁止自动降级全量、禁止自动扩展题材)。脚本停止并输出推荐题材关键词, 由 Agent 询问用户是否按推荐词重新查询,得到用户确认后才可发起查询。 - 全量查询数据不足(小于 AUTO_EXPAND_THRESHOLD)时仅提示推荐题材并等待确认, 已获取的数据仍正常生成日报。 v2.3.1 调整说明(相关词命中直查): - 【相关词命中直查】关键词校验匹配 topic_keywords 中规定的**题材名+全部相关词** (如「打脸」命中逆袭题材相关词、「总裁」命中霸总题材相关词、「宠妻/替身」命中 霸总相关词等),命中后**直接使用该关键词查询数据**(不替换题材、不降级全量)。 v2.2 调整说明(同步自"短剧-B站信息源" v2.2 增强 + 用户新规则): - 【前置校验】查询前先判断用户的输入条件: 1) 分类/关键词是否符合短剧题材词库(穿越/霸总/重生/甜宠/悬疑等) 2) 日期是否在有效查询范围(格式正确、不晚于今天) - 【不满足不请求接口】关键词/分类不满足短剧题材词库时,明确提醒"关键词不满足 查询条件"并推荐相关分类和关键词,**不发起任何接口请求**(避免浪费API额度), 直接停止并引导用户改用推荐词重新查询。 - 【日期兜底】用户查询的日期未更新或超过查询时间范围时,自动向前回退获取最近 时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动 获取最近时间范围数据"。 v2.0 增强说明(同步自B站版,针对"数据查询结果为空"问题的降失败率机制): 1. 【P0-日期探活】查询前先用 pageSize=1、不带 keyword 的轻量请求探测目标日期 是否有数据;无数据立即拦截,避免盲目消耗多题材查询额度。 2. 【P0-自动回退】--latest 从最近日期向前最多回退 FALLBACK_DAYS(默认7) 天, 找到第一个有数据的日期再生成日报;输出中明确标注实际数据日期。 3. 【确认制-扩展题材】全量查询数据不足(小于 AUTO_EXPAND_THRESHOLD)时, 不再自动扩展题材;提示 穿越→霸总→重生→悬疑→甜宠→逆袭 推荐顺序, 由 Agent 询问用户确认后才按 --topics 重新查询。 4. 【P1-空结果重试】单题材查询为空/异常时,间隔 RETRY_INTERVAL 秒重试 1 次。 5. 【P1-题材词校验】--topics 传入明显非题材词时给出提示(不阻断,仅提醒)。 6. 【P2-结构化空因】每次空结果输出原因分类:无数据 / 关键词无匹配 / API异常。 7. 【P2-防御式解析】兼容 {"code":2000,"data":{"list":[...]}} 与直出 list 两种 格式,防止服务端调整响应结构时脚本静默失效。 公众号平台适配(相对抖音版): - platform=0(公众号) - 排序与展示以阅读量 readCount 为核心指标 - 账号字段多字段兜底 verifyName / accountName / author - 文章链接多字段兜底 url / workUrl / articleUrl - 主题色 #07C160(微信绿) 用法与原版完全兼容: python3 playlet_wechat_daily.py --latest python3 playlet_wechat_daily.py --date 2026-08-05 python3 playlet_wechat_daily.py --topics "穿越,霸总" --latest """ import argparse import json import os import sys import time import webbrowser from datetime import datetime, timedelta from urllib import request, error # ============ 配置 ============ API_BASE_URL = "https://redfox.hk/story/api/parseWork/queryPlayletMsgs" CACHE_DIR = os.path.expanduser("~/.workbuddy/cache") CACHE_FILE = os.path.join(CACHE_DIR, "playlet_wechat_data.json") OUTPUT_DIR = os.path.expanduser("~/Downloads/QoderReports") DATA_UPDATE_HOUR = 15 # 数据源声称的更新时刻(仅作提示参考,不再作为唯一依据) FALLBACK_DAYS = 7 # --latest 自动回退的最大天数 RETRY_TIMES = 1 # 空结果/异常重试次数 RETRY_INTERVAL = 4 # 重试间隔(秒) REQUEST_TIMEOUT = 30 # 单次请求超时(秒) AUTO_EXPAND_THRESHOLD = 100 # 全量结果少于该值时提示用户确认是否扩展题材(不自动扩展) AUTO_EXPAND_TOPICS = ["穿越", "霸总", "重生", "悬疑", "甜宠", "逆袭"] # 推荐扩展顺序(仅供提示,需用户确认后才查询) HOT_TOPICS = ["穿越", "霸总", "重生", "悬疑", "甜宠", "逆袭", "年代", "战神", "古装"] # 推荐题材顺序 # 短剧题材词库:用于 --topics 输入校验提示 # 规则:关键词需命中 topic_keywords 中规定的题材名+全部相关词(如「打脸」命中逆袭题材相关词),命中后直接用该关键词查询数据 TOPIC_KEYWORDS_THESAURUS = { "穿越": ["穿越", "时空", "古代", "现代", "回到", "大宋", "北宋", "南宋", "唐朝", "明朝", "清朝"], "霸总": ["霸总", "总裁", "豪门", "冷酷", "宠妻", "娇妻", "替身"], "重生": ["重生", "逆袭", "回到", "翻盘", "重来", "再生"], "悬疑": ["悬疑", "推理", "反转", "惊悚", "谜案", "秘密", "真相"], "甜宠": ["甜宠", "恋爱", "撒糖", "甜蜜", "宠溺", "甜甜"], "逆袭": ["逆袭", "翻身", "打脸", "崛起", "反击", "报复"], "年代": ["年代", "八零", "九零", "七零", "六零"], "战神": ["战神", "龙王", "兵王", "高手"], "古装": ["古装", "宫廷", "皇后", "贵妃", "王爷", "世子"], } # 全部有效词集合(题材名 + 各题材相关词 + 扩展词),用于关键词前置校验 TOPIC_THESAURUS = { "穿越", "霸总", "重生", "悬疑", "甜宠", "逆袭", "年代", "战神", "古装", "总裁", "豪门", "复仇", "惊悚", "推理", "反转", "爽文", "科幻", "玄幻", "修仙", "都市", "职场", "萌宝", "萌娃", "亲子", "离婚", "闪婚", "替身", "虐恋", "先婚后爱", "双重生", } for _t, _kws in TOPIC_KEYWORDS_THESAURUS.items(): TOPIC_THESAURUS.add(_t) TOPIC_THESAURUS.update(_kws) # ============ 工具函数 ============ def get_api_key(): """从环境变量获取 API Key""" api_key = os.environ.get("REDFOX_API_KEY") if not api_key: print("❌ 错误:未找到 REDFOX_API_KEY 环境变量") print("请先配置:export REDFOX_API_KEY=<你的apikey>") sys.exit(1) return api_key def calculate_latest_date(): """按15:00规则估算最新可用日期(仅作初始起点,实际以探活为准)""" now = datetime.now() if now.hour < DATA_UPDATE_HOUR: return (now - timedelta(days=2)).strftime("%Y-%m-%d") else: return (now - timedelta(days=1)).strftime("%Y-%m-%d") def validate_date(date_str): """旧接口保留:基于本地时钟的日期校验(新逻辑改走 probe_date)""" latest_date = calculate_latest_date() target_date = datetime.strptime(date_str, "%Y-%m-%d") latest = datetime.strptime(latest_date, "%Y-%m-%d") return target_date <= latest, latest_date def check_topics(topics): """ v2.2 前置校验:判断用户输入的分类/关键词是否符合短剧题材词库。 返回 (有效词列表, 无效词列表, 推荐词列表) 推荐逻辑:优先从无效词中提取包含的题材词,再补充热门题材词。 """ hot_topics = ["穿越", "霸总", "重生", "甜宠", "悬疑", "逆袭", "年代", "战神", "古装", "都市", "科幻"] valid, invalid = [], [] for t in topics: if t in TOPIC_THESAURUS or t == "短剧": valid.append(t) else: invalid.append(t) recommends = [] for t in invalid: # 无效词若包含题材词(如"穿越重生"含"穿越""重生"),优先推荐 contained = [w for w in TOPIC_THESAURUS if w in t or t in w] for c in contained: if c not in recommends: recommends.append(c) for h in hot_topics: if h not in recommends: recommends.append(h) return valid, invalid, recommends def check_date(date_str): """ v2.2 前置校验:判断日期是否在有效查询范围(格式正确、不晚于今天)。 返回 (是否有效, 提示信息, 推荐日期或None) """ try: d = datetime.strptime(date_str, "%Y-%m-%d") except ValueError: return False, f"日期格式无效:{date_str}(应为 YYYY-MM-DD)", None today = datetime.now().date() if d.date() > today: latest = calculate_latest_date() return False, f"日期 {date_str} 超出有效查询范围(晚于今天,数据每日15:00更新前一天)", latest return True, "", None def parse_response(result): """ 防御式响应解析(加固,非修复):兼容两种格式 格式A(API实际完整响应): {"code":2000,"data":{"list":[...],"total":M},"msg":"..."} 格式B(兜底/直出): {"list":[...], "pageNum":1, "pages":N, "total":M} 返回: (items列表, error_msg或None) """ if not isinstance(result, dict): return [], "响应非JSON对象" # 格式A:code/data 包装(当前 API 实际格式) if result.get("code") == 2000: data = result.get("data") or {} return data.get("list") or [], None # 显式业务错误 code = result.get("code") if code is not None: msg = result.get("msg") return [], f"API业务错误 code={code} msg={msg}" # 格式B:直出 list(兜底) if "list" in result: return result.get("list") or [], None return [], None def http_post(payload, api_key): """执行一次 POST 请求,返回原始响应 dict(网络/HTTP 层异常向上抛)""" data = json.dumps(payload).encode('utf-8') req = request.Request( API_BASE_URL, data=data, headers={ "Content-Type": "application/json", "X-API-KEY": api_key }, method="POST" ) with request.urlopen(req, timeout=REQUEST_TIMEOUT) as response: return json.loads(response.read().decode('utf-8')) def build_payload(start_time, end_time, keyword=None, page_size=200): """构建请求体;keyword 为 None 时表示全量查询(不带 keyword 字段)""" payload = { "msgType": "短剧", "platform": 0, # 0=公众号 "source": "短剧公众号信息源-GitHub", "pageNum": 1, "pageSize": page_size, "startTime": start_time, "endTime": end_time, } if keyword: payload["keyword"] = keyword return payload def probe_date_available(api_key, start_time, end_time): """ 探活:pageSize=1 + 不带 keyword 的轻量请求,确认该日期是否有数据。 返回 (bool, info_str);False 说明该日期数据源无任何数据(未更新/缺失)。 成本:每次探测约 1 次接口额度,远低于无脑全量查询。 """ payload = build_payload(start_time, end_time, keyword=None, page_size=1) try: result = http_post(payload, api_key) items, err = parse_response(result) if err: print(f" ⚠️ 探活请求异常: {err}") return False, "probe_error" if items: return True, "ok" return False, "no_data" except Exception as e: print(f" ⚠️ 探活请求失败: {e}") return False, "probe_fail" def _fetch_topic_once(api_key, payload, topic): """单题材单次查询(含重试),返回 (items, api_error: bool)""" for attempt in range(RETRY_TIMES + 1): try: result = http_post(payload, api_key) items, err = parse_response(result) if err: if attempt < RETRY_TIMES: time.sleep(RETRY_INTERVAL) continue return items, False # 解析成功(可能为空 list,但非异常) except Exception as e: if attempt < RETRY_TIMES: print(f" ⚠️ 题材 {topic} 第{attempt+1}次请求失败({e}),{RETRY_INTERVAL}s后重试...") time.sleep(RETRY_INTERVAL) else: print(f"❌ 查询题材 {topic} 失败:{str(e)}") return [], True # ============ 数据获取 ============ def fetch_playlet_data( topics=None, start_time=None, end_time=None, count=200, use_cache=False, ): """ 调用 API 查询公众号短剧数据(增强版) Args: topics: 题材列表(逗号分隔),None/空 → 全量查询;数据不足时不自动扩展,提示用户确认 start_time / end_time: 查询时间窗 count: 扫描作品数量 use_cache: 是否使用缓存 Returns: (items, meta) 其中 meta 含 reason 字段用于结构化空因: reason in {"ok", "no_data", "probe_fail", "probe_error", "keyword_no_match", "api_error"} """ if use_cache: cached_data = load_cache() if cached_data: print("📦 使用缓存数据") return cached_data, {"reason": "ok", "note": "cache"} if not start_time or not end_time: latest_date = calculate_latest_date() start_time = f"{latest_date} 00:00:00" end_time = f"{latest_date} 23:59:59" api_key = get_api_key() meta = {"reason": "ok", "probed": False, "date": start_time[:10]} # ---- P0-2 探活:先确认该日期数据源是否有数据 ---- available, info = probe_date_available(api_key, start_time, end_time) meta["probed"] = True if not available: meta["reason"] = "no_data" if info == "no_data" else info print(f"📭 日期 {start_time[:10]} 数据源无数据({info}),跳过查询以避免浪费额度") return [], meta # ---- 确定查询题材序列 ---- # 用户指定题材 → 仅用用户列表(确认制:无匹配时不再自动降级/扩展) # 未指定 → 全量查询;数据不足时提示推荐题材并等待用户确认,不自动扩展 if topics: query_topics = list(topics) auto_expand = False else: query_topics = [None] auto_expand = True all_items = [] api_errors = 0 for topic in query_topics: keyword = None if topic is None or topic == "短剧" else topic payload = build_payload(start_time, end_time, keyword=keyword, page_size=min(count, 200)) items, had_error = _fetch_topic_once(api_key, payload, topic or "全量") if had_error: api_errors += 1 if items: all_items.extend(items) # ---- 确认制(v2.3):全量数据不足时不再自动扩展题材 ---- # 仅提示推荐题材并等待用户确认,确认前不发起任何额外请求 if auto_expand: unique_ids = {it.get("photoId") for it in all_items if it.get("photoId")} if len(unique_ids) < min(count, AUTO_EXPAND_THRESHOLD): print(f" ⚠️ 全量数据不足({len(unique_ids)}条 < {AUTO_EXPAND_THRESHOLD}),不自动扩展题材") print(f" 💡 推荐题材: {'、'.join(AUTO_EXPAND_TOPICS)}") print(f" ❓ 请确认是否按推荐题材扩展查询(使用 --topics 重新查询),确认前不会发起任何额外请求") meta["reason"] = "need_confirm_expand" # 去重(基于photoId) seen = set() unique_items = [] for item in all_items: item_id = item.get("photoId") if item_id and item_id not in seen: seen.add(item_id) unique_items.append(item) # 按阅读量排序(公众号核心指标是阅读量而非点赞量) unique_items.sort(key=lambda x: x.get("readCount", 0), reverse=True) if not unique_items: # 探活通过但实际查询为空 → 大概率是关键词无匹配 if topics and topics != [None]: meta["reason"] = "keyword_no_match" else: meta["reason"] = "no_data" return [], meta # 保存缓存 save_cache(unique_items) meta["reason"] = "ok" return unique_items[:count], meta # ============ 题材聚类 ============ def cluster_by_topic(items): """按题材聚类文章(词库与 TOPIC_KEYWORDS_THESAURUS 保持一致)""" topic_keywords = dict(TOPIC_KEYWORDS_THESAURUS) clusters = {} for item in items: title = item.get("title", "") matched_topics = [] for topic, keywords in topic_keywords.items(): if any(kw in title for kw in keywords): matched_topics.append(topic) matched_topic = matched_topics[0] if matched_topics else "其他" clusters.setdefault(matched_topic, []).append(item) return clusters # ============ HTML 日报 ============ def format_number(num): """格式化数字(万→w)""" if num is None: return "0" if num >= 10000: return f"{num/10000:.1f}w" return str(num) def generate_html_report(items, clusters, date_str): """生成HTML日报(微信绿 #07C160,阅读/点赞/评论零值隐藏)""" os.makedirs(OUTPUT_DIR, exist_ok=True) html_file = os.path.join(OUTPUT_DIR, f"短剧公众号日报_{date_str}.html") try: dt_obj = datetime.strptime(date_str, "%Y-%m-%d") weekdays = ["一", "二", "三", "四", "五", "六", "日"] date_cn = f"{dt_obj.year}年{dt_obj.month}月{dt_obj.day}日 星期{weekdays[dt_obj.weekday()]}" except ValueError: date_cn = date_str total_count = len(items) topic_count = len(clusters) total_reads = sum(item.get("readCount", 0) for item in items) avg_reads = total_reads / total_count if total_count > 0 else 0 category_cards = "" for i, (topic, topic_items) in enumerate( sorted(clusters.items(), key=lambda x: len(x[1]), reverse=True), 1): articles_html = "" for item in topic_items[:5]: title = item.get("title", "无标题") author = item.get("verifyName", "") or item.get("accountName", "") or item.get("author", "") # 公众号字段,多字段兜底 cover = item.get("coverUrl") or "" raw_reads = item.get("readCount") or 0 raw_likes = item.get("likeCount") or 0 raw_comments = item.get("commentCount") or 0 reads = format_number(raw_reads) # 阅读量 likes = format_number(raw_likes) # 点赞数 comments = format_number(raw_comments) # 评论数 url = item.get("url", "") or item.get("workUrl", "") or item.get("articleUrl", "") # 文章链接,多字段兜底 cover_html = "" if cover: cover_html = f'<img class="article-cover" src="{cover}" alt="" loading="lazy">' # 文章标题改为可点击链接 if url: title_html = f'<a class="article-title" href="{url}" target="_blank" rel="noopener noreferrer">{title}</a>' else: title_html = f'<span class="article-title">{title}</span>' # 各项数据为0时不展示该字段 metrics_parts = [] if raw_reads > 0: metrics_parts.append(f'<span class="metric">👁 {reads}</span>') if raw_likes > 0: metrics_parts.append(f'<span class="metric">👍 {likes}</span>') if raw_comments > 0: metrics_parts.append(f'<span class="metric">💬 {comments}</span>') metrics_html = "\n ".join(metrics_parts) if metrics_parts else "" articles_html += f''' <div class="article-item"> {cover_html} <div class="article-info"> {title_html} <div class="article-meta"> <span class="author">{author}</span> <span class="metrics"> {metrics_html} </span> </div> </div> </div>''' category_cards += f''' <div class="category-card reveal"> <div class="card-header"> <span class="card-number">{i:02d}</span> <h3 class="card-category">#{topic}</h3> <span class="card-count">{len(topic_items)} 篇</span> </div> <div class="card-body">{articles_html} </div> </div>''' timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") html_content = f'''<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>短剧-公众号信息源 - {date_str}</title> <style> * {{ margin: 0; padding: 0; box-sizing: border-box; }} body {{ font-family: -apple-system, sans-serif; background: #1a1a1a; color: #e8e4df; padding: 2rem; }} .header {{ text-align: center; padding: 2rem 0; }} .header h1 {{ font-size: 2rem; color: #07C160; }} .header p {{ color: #9a9590; margin-top: 0.5rem; }} .stats {{ display: flex; justify-content: center; gap: 2rem; padding: 1rem; margin: 1rem 0; }} .stat-item {{ text-align: center; }} .stat-value {{ font-size: 1.5rem; font-weight: bold; color: #07C160; }} .stat-label {{ font-size: 0.8rem; color: #9a9590; }} .cards {{ display: grid; grid-template-columns: repeat(auto-fill, minmax(360px, 1fr)); gap: 1.5rem; max-width: 1200px; margin: 2rem auto; }} .category-card {{ background: #2d2d2d; border-radius: 12px; padding: 1.5rem; }} .card-header {{ display: flex; align-items: center; gap: 0.8rem; margin-bottom: 1rem; padding-bottom: 0.8rem; border-bottom: 1px solid #3d3d3d; }} .card-number {{ font-size: 1.5rem; font-weight: bold; color: #07C160; }} .card-category {{ flex: 1; font-size: 1.1rem; }} .card-count {{ color: #9a9590; font-size: 0.9rem; }} .article-item {{ padding: 0.6rem 0; border-bottom: 1px solid #3d3d3d; display: flex; gap: 0.8rem; }} .article-item:last-child {{ border-bottom: none; }} .article-cover {{ width: 60px; height: 60px; border-radius: 6px; object-fit: cover; flex-shrink: 0; }} .article-info {{ flex: 1; min-width: 0; }} .article-title {{ color: #e8e4df; font-size: 0.9rem; line-height: 1.4; display: block; text-decoration: none; transition: color 0.2s; }} .article-title:hover {{ color: #07C160; }} .article-meta {{ display: flex; justify-content: space-between; margin-top: 0.3rem; font-size: 0.75rem; color: #9a9590; }} .metrics {{ display: flex; gap: 0.8rem; }} .footer {{ text-align: center; padding: 2rem; color: #666; font-size: 0.8rem; }} .reveal {{ animation: fadeIn 0.5s ease-in; }} @keyframes fadeIn {{ from {{ opacity: 0; transform: translateY(20px); }} to {{ opacity: 1; transform: translateY(0); }} }} </style> </head> <body> <div class="header"> <h1>📱 短剧-公众号信息源</h1> <p>{date_cn} | 共 {total_count} 篇热门短剧文章</p> </div> <div class="stats"> <div class="stat-item"><div class="stat-value">{topic_count}</div><div class="stat-label">题材</div></div> <div class="stat-item"><div class="stat-value">{total_count}</div><div class="stat-label">文章</div></div> <div class="stat-item"><div class="stat-value">{format_number(int(avg_reads))}</div><div class="stat-label">平均阅读</div></div> <div class="stat-item"><div class="stat-value">{format_number(total_reads)}</div><div class="stat-label">总阅读</div></div> </div> <div class="cards">{category_cards}</div> <div class="footer">Generated at {timestamp} by 短剧-公众号信息源 Skill<br>数据说明:每日15:00更新前一天的数据 | 数据来源:红狐Hub</div> </body> </html>''' with open(html_file, 'w', encoding='utf-8') as f: f.write(html_content) return html_file # ============ 缓存 ============ def load_cache(): if not os.path.exists(CACHE_FILE): return None try: with open(CACHE_FILE, 'r', encoding='utf-8') as f: cache_data = json.load(f) if time.time() - cache_data.get("timestamp", 0) < 3600: return cache_data.get("items") except Exception: pass return None def save_cache(items): os.makedirs(CACHE_DIR, exist_ok=True) cache_data = {"timestamp": time.time(), "items": items} try: with open(CACHE_FILE, 'w', encoding='utf-8') as f: json.dump(cache_data, f, ensure_ascii=False, indent=2) except Exception: pass # ============ 主流程 ============ def find_latest_available_date(api_key, max_fallback=FALLBACK_DAYS): """ P0-2 自动回退:从最近日期开始向前探测,返回第一个有数据的日期。 返回 (date_str, found: bool) """ latest = calculate_latest_date() cursor = datetime.strptime(latest, "%Y-%m-%d") for i in range(max_fallback + 1): d = (cursor - timedelta(days=i)).strftime("%Y-%m-%d") print(f" 🔎 探测 {d} ...", end="") ok, info = probe_date_available( api_key, f"{d} 00:00:00", f"{d} 23:59:59" ) print(" 有数据" if ok else f" 无数据({info})") if ok: return d, True return latest, False def main(): global OUTPUT_DIR parser = argparse.ArgumentParser(description="短剧-公众号信息源日报生成工具 (v2.3确认制)") parser.add_argument("--topics", type=str, help="题材关键词,逗号分隔;不满足短剧题材词时提醒并推荐,不请求接口") parser.add_argument("--count", type=int, default=200, help="扫描文章数量") parser.add_argument("--date", type=str, help="指定日期 YYYY-MM-DD;超出有效范围时提醒并自动回退最近有数据的日期") parser.add_argument("--start-time", type=str, help="开始时间 YYYY-MM-DD HH:MM:SS") parser.add_argument("--end-time", type=str, help="结束时间 YYYY-MM-DD HH:MM:SS") parser.add_argument("--latest", action="store_true", help="使用最新有数据的日期(自动回退)") parser.add_argument("--output-dir", type=str, default=OUTPUT_DIR, help="输出目录") parser.add_argument("--api-key", type=str, help="指定 API Key") parser.add_argument("--subscribe", action="store_true", help="开启每日订阅") parser.add_argument("--unsubscribe", action="store_true", help="关闭每日订阅") parser.add_argument("--from-cache", action="store_true", help="使用缓存数据") args = parser.parse_args() if args.subscribe: print("✅ 已开启每日订阅,日报将自动保存至:", OUTPUT_DIR) return if args.unsubscribe: print("✅ 已关闭每日订阅") return if args.output_dir: OUTPUT_DIR = args.output_dir api_key = args.api_key or get_api_key() # ---- 前置校验:关键词/分类是否符合短剧题材词库(不满足则不请求接口)---- topics = None if args.topics: raw_topics = [t.strip() for t in args.topics.split(",") if t.strip()] valid_topics, invalid_topics, recommends = check_topics(raw_topics) if invalid_topics: print(f"⚠️ 关键词 {invalid_topics} 不满足短剧查询条件(短剧按题材/剧情词匹配标题,非短剧题材词大概率无结果)") print(f"💡 推荐相关分类和关键词:{'、'.join(recommends[:10])}") if valid_topics: print(f"✅ 已保留有效关键词 {valid_topics} 继续查询,无效关键词已自动忽略") topics = valid_topics else: print("🛑 关键词均不满足短剧查询条件,未发起任何接口请求。请使用推荐题材词重新查询。") return else: topics = valid_topics # ---- 确定查询日期 ---- if args.start_time: start_time = args.start_time date_str = args.start_time[:10] end_time = args.end_time or f"{date_str} 23:59:59" elif args.latest: # P0-2 自动回退:探测最近有数据的日期 print(f"🔎 --latest: 自动寻找最近有数据的日期(最多回退{FALLBACK_DAYS}天)...") date_str, found = find_latest_available_date(api_key) if not found: print(f"📭 最近 {FALLBACK_DAYS} 天内均无数据,请稍后再试或联系数据源确认更新状态") return start_time = f"{date_str} 00:00:00" end_time = f"{date_str} 23:59:59" print(f"✅ 已定位最新可用日期: {date_str}") elif args.date: date_str = args.date # v2.2: 前置校验——日期格式与有效查询范围 date_ok, date_msg, date_suggest = check_date(date_str) if not date_ok: print(f"⚠️ {date_msg}") if date_suggest: print(f"💡 推荐查询时间范围:{date_suggest}(已为您自动获取该时间范围数据)") # 探活式预检(替代纯本地时钟判断) ok, info = probe_date_available(api_key, f"{date_str} 00:00:00", f"{date_str} 23:59:59") if not ok: # v2.1: 日期兜底——未更新/超范围时自动回退最近有数据的日期,不再等待确认 print(f"⚠️ 当前查询时间 {date_str} 未更新或超过查询时间范围,已为您自动获取最近时间范围数据...") new_date, found = find_latest_available_date(api_key) if not found: print(f"📭 最近 {FALLBACK_DAYS} 天内均无数据,请稍后再试或联系数据源确认更新状态") return print(f"✅ 已为您自动获取最近时间范围数据: {new_date}(原查询 {date_str} 未更新或超过查询时间范围)") date_str = new_date start_time = f"{date_str} 00:00:00" end_time = f"{date_str} 23:59:59" else: date_str = calculate_latest_date() start_time = f"{date_str} 00:00:00" end_time = f"{date_str} 23:59:59" print(f"🔍 正在查询 {date_str} 的公众号短剧数据...") items, meta = fetch_playlet_data( topics=topics, start_time=start_time, end_time=end_time, count=args.count, use_cache=args.from_cache, ) if not items: reason = meta.get("reason", "unknown") hint = { "no_data": "数据源当日无数据(未更新或缺失)", "probe_fail": "探测请求失败(网络/接口异常)", "probe_error": "探测请求异常(接口返回异常)", "keyword_no_match": "查询条件(题材词)在该日期无匹配作品", "api_error": "接口调用异常", }.get(reason, "未知原因") print(f"📭 未查询到相关数据 [原因: {hint}]") if reason == "keyword_no_match": # v2.3 确认制:无匹配数据时展示推荐关键词,等待用户确认后才可查询,禁止自动查询 print("🛑 未发起任何额外查询(禁止自动降级全量 / 自动扩展题材)") print(f"💡 推荐题材:{'、'.join(AUTO_EXPAND_TOPICS)}、年代、战神、古装、都市") print(f"❓ 是否按推荐题材(如 {AUTO_EXPAND_TOPICS[0]}/{AUTO_EXPAND_TOPICS[1]})重新查询?" f"请确认后使用 --topics 重新查询。") elif reason == "no_data": print("💡 建议: 使用 --latest 自动回退到最近有数据的日期") return print(f"✅ 共获取 {len(items)} 篇短剧文章") if meta.get("reason") == "need_confirm_expand": # v2.3 确认制:全量数据不足时未自动扩展,提示推荐题材并等待用户确认 print(f"⚠️ 全量数据不足,未自动扩展题材(禁止自动查询)。推荐题材:{'、'.join(AUTO_EXPAND_TOPICS)}") print(f"❓ 是否按推荐题材扩展查询?请确认后使用 --topics 重新查询(确认前不发起额外请求)。") clusters = cluster_by_topic(items) print(f"📊 聚类为 {len(clusters)} 个题材方向") html_file = generate_html_report(items, clusters, date_str) print(f"📄 日报已生成:{html_file}") webbrowser.open(f"file://{html_file}") print(f"\n## 短剧-公众号信息源 · {date_str} 日报\n") print(f"**扫描 {len(items)} 篇热门短剧文章,聚类 {len(clusters)} 个题材方向**\n") print("### 题材概览\n") print("| 题材 | 数量 | 占比 | 爆款亮点 |") print("|------|------|------|---------|") for topic, topic_items in sorted(clusters.items(), key=lambda x: len(x[1]), reverse=True): top_item = topic_items[0] if topic_items else {} print(f"| #{topic} | {len(topic_items)}篇 | {len(topic_items)/len(items)*100:.1f}% | 《{top_item.get('title', '')[:20]}》{format_number(top_item.get('readCount', 0))}阅读 |") if __name__ == "__main__": main()
-
-
README.en.md 10.8 KB
# Playlet WeChat Official Accounts Feed / playlet-wechat-feed --- ## Overview Playlet WeChat Official Accounts Feed is a trending content tracking tool designed for short drama creators and content operators. It scans WeChat official account short drama content daily, filters popular works by read count, intelligently clusters by genre direction, and generates a visualized HTML daily report with creative trend analysis. **Core Value** - 🔥 Discover trending short drama articles from WeChat official accounts and pinpoint high-engagement works - 📊 Get genre-clustered popular content at a glance to understand hotspot distribution - 📈 Analyze trending title patterns and creative trends to uncover traffic strategies - 🔔 Enable daily subscription for automatic report generation and intelligence system setup **Target Users** - ✍️ Short Drama Scriptwriters — Identify genre trends and improve topic selection accuracy - 📱 Content Operators — Track daily short drama trends from WeChat official accounts and drive content decisions - 🏢 MCN Agencies — Monitor industry dynamics and manage multi-account content direction - 📝 Official Account Owners — Discover benchmark accounts and trending content to optimize creative strategies --- ## Features ### Core Features - **Trending Discovery** — Filter popular short drama content from WeChat official accounts by read count, precisely locating high-engagement works - **Genre Clustering** — Automatically identify genre directions (Time Travel / CEO Romance / Rebirth / Suspense / Sweet Romance / Comeback / Period Drama / War God / Historical), with daily dynamic genre classification - **Smart Query** — Query all short drama content by default, automatically expanding genre batch queries when data is insufficient to save API quota - **Custom Query** — Support targeted queries by genre, official account, or keywords, flexibly covering any short drama niche - **Creative Insights** — Analyze trending title patterns, genre trends, and official account performance for in-depth creative pattern discovery - **Visual Daily Report** — Dark-themed HTML report with cover images, engagement data, and direct article links - **One-Click Subscription** — Automatically generate daily reports saved to local folder after activation ### Highlights - ⚡ **Batch Query** — Query all genres at once via batch API, efficiently reducing API call count - 🧠 **Smart Clustering** — Auto-classify into 9 genres with dynamic daily adjustment - 💾 **Caching** — 1-hour validity to avoid duplicate requests and enable quick result review - 📅 **Intelligent Date Check** — Automatically validate target date availability to avoid invalid calls --- ## API Key Acquisition & Security - This skill requires the environment variable: `REDFOX_API_KEY`. - `REDFOX_API_KEY` is provided by [RedFoxHub](https://redfox.hk/settings/api-keys?source=github) (`https://redfox.hk`). - Please visit [RedFoxHub](https://redfox.hk?source=github) to register and obtain your `REDFOX_API_KEY`. - Configure the environment variable `REDFOX_API_KEY` on your device before using this skill. - Before providing your key, verify its source, available scope, expiration date, and whether it supports reset/revocation. - Never hardcode or expose your API key in plain text within code, prompts, logs, or output files. --- ## Usage Guide Simply describe your needs in natural language — no commands to memorize. ### Quick Reference | Intent | Example Phrase | Result | |--------|---------------|--------| | Latest Report | "Show me today's short drama WeChat report" | Generate the latest visualized daily report | | Query by Genre | "Short drama articles in the time travel genre", "Show me CEO romance and sweet romance content" | Get trending content in specified genres | | Query by Time | "What are the short drama trends this month", "Short drama hits in June" | Analyze content trends over a period | | Historical Review | "Do you have the short drama WeChat report for June 10th" | View trending data for a specific date | | Combined Query | "Time travel genre short dramas in June" | Precisely locate specific genre + time range | | Subscription | "Enable daily short drama report subscription" | Auto-generate and save daily reports | | Quick Cache View | "Show me the last short drama results from cache" | Quick view without API call within 1 hour | ### Sample Output After generating the report, the terminal outputs a genre classification table and creative trend analysis report, while a dark-themed HTML visual report is generated and automatically opened in the browser. The HTML report includes: - Genre card layout clearly showing genre distribution - Each article displays cover image, title, official account name, read count, likes, and comments (fields with 0 value are automatically hidden) - Statistics panel: genre count, article count, average reads, total reads Below is a real output example from 2026-06-15: --- ## Playlet WeChat Feed · 2026-06-15 Daily Report **Scanned 176 trending short drama articles, clustered into 6 genre directions** --- ### Genre Overview | Genre | Count | Share | Highlight | |-------|-------|-------|-----------| | #Other | 156 | 88.6% | "Value Upgrade: The 2.0 Era of Short Dramas and Celebrities" 23k reads, AI short drama tool content surging | | #SweetRomance | 7 | 4.0% | "Hot Plant Whisper" cozy bedtime stories, avg 800+ reads, stable audience | | #CEORomance | 6 | 3.4% | Clara transitioning to short drama actress sparks discussion, top article 4,905 reads | | #Suspense | 3 | 1.7% | "Truth Behind Short Drama Actor's Passing" 3,801 reads, gossip content drives strong engagement | | #TimeTravel | 3 | 1.7% | Shaanxi short drama base's million-yuan sets face cold reception, industry analysis content gains traction | | #Historical | 1 | 0.6% | "Historical Hairstyle Prompts for Short Dramas" 1,058 reads, AI creation-assist content breaks out | --- ### Creative Trend Analysis **I. Emerging Growth Signals** - 🔥 **#Historical** — Only 1 article but 3.6% like rate (38 likes / 1,058 reads), AI-assisted creation tools show engagement far above average, prompt/workflow content has sustained breakout potential - 🔥 **#Suspense** — Only 3 articles but top read at 3,801, gossip + industry insider combo titles outperform market average **II. Trending Title Patterns** | Pattern | Occurrences | Example | Avg Reads | |---------|-------------|---------|-----------| | Exclamation emotional hook (!) | 93 | "OiiOii 2.0 Major Upgrade, Short Drama E-commerce Is About to Explode..." | 1,374 | | Question suspense hook (?) | 55 | "As Boundaries Blur, What Opportunities Exist for Actors in the 100B Short Drama Market?" | 1,325 | | "N titles" listicle format | 13 | "5 Addictive High-Rated Short Dramas! CEO Romance, Urban Healing" | 1,072 | | AI + tool/platform name | 15 | "700M Plays, I Found the Godly Tool Behind These AI Short Dramas!" | ~6,500 | **III. Top Official Accounts** No official account data available (API did not return accountName field today) **IV. Genre Trend Report** **Genre**: #SweetRomance **Count**: 7 articles **Avg Reads**: ~900 **Top Work**: "Hot Plant Whisper" by Dick Lamb (cozy sweet bedtime story) — 1,258 reads **Genre Traits**: Sweet romance focuses on "bedtime stories," "couple avatars," and "hidden gem recommendations." Titles typically include emotional keywords like "sweet," "healing," and "happy ending." Audience stickiness is high but traffic ceiling is relatively low. **Creative Advice**: Combine "CP-oriented" fan content and cross-genre tags (sweet romance × historical, sweet romance × time travel) for broader reach. Add completion-promise hooks like "binge-worthy," "hidden gem," or "super sweet ending" to boost clicks. **V. #CEORomance** **Genre**: #CEORomance **Count**: 6 articles **Avg Reads**: ~2,911 **Top Work**: "'Asia's Most Beautiful Woman' Clara, Rejected by Elite Family, Transitions to Short Drama Actress!" — 4,905 reads **Genre Traits**: Today's CEO romance buzz is driven by "celebrity entering short dramas" gossip rather than traditional CEO romance plot recommendations. Contrast words like "elite family," "career switch," and "rejected" form the core traffic hooks. **Creative Advice**: Leverage celebrity/actor news as entry points for CEO romance content. Use "identity contrast + twist" title formula (e.g., "Rejected by XX, transitions to XX"). Combine with "high-rated collection" listicles for long-tail traffic. **VI. #Suspense** **Genre**: #Suspense **Count**: 3 articles **Avg Reads**: ~2,047 **Top Work**: "Truth Behind Short Drama Actor's Passing, Angela An Returns, Minghao Hou Testing Waters..." — 3,801 reads **Genre Traits**: Suspense content today presents as "industry gossip + truth reveals." Titles chain multiple celebrity names with suspense question marks. Anti-fraud AI micro-drama (1,718 reads) represents policy-driven content; overall count is low but per-article engagement exceeds market average. **Creative Advice**: Suspense on WeChat works better for "insider reveals" and "truth reconstruction" non-fiction directions. Stack multiple celebrity/event names in titles for information density. Watch for "anti-fraud" and "social issues" policy trends for platform traffic boosts. **VII. Cross-Genre Comparison** - **#CEORomance × #SweetRomance** — Monitor "CEO sweet romance" compound tag collaborations. Today's "5 Addictive High-Rated Short Dramas! CEO Romance, Urban Healing" (2,606 reads) validates the compound genre collection format. Further audience overlap analysis recommended. - **#AIShortDrama (hidden theme within Other) × All Genres** — Today's 38 AI short drama articles averaged 2,630 reads, far exceeding the market average of 1,994. "Production tutorials / tool reviews" combining AI tools with any genre represent a significant traffic opportunity. Creators across all genres should pay attention to AI production workflow content. --- **Report Path**: `C:\Users\Downloads\QoderReports\短剧公众号日报_2026-06-15.html` > Data note: Updated daily at 15:00 with previous day's data --- ## Use Cases | Scenario | Role | Example Query | Benefit | |----------|------|--------------|---------| | Topic Research | Scriptwriter | "What short drama genres are trending lately? Analyze time travel and rebirth for me" | Identify genre trends and improve topic selection accuracy | | Report Tracking | Content Operator / MCN | "Enable daily report subscription to track WeChat short drama trends for me" | Build a team intelligence system and drive content decisions | | Competitor Analysis | Brand Manager / Ad Manager | "Show me CEO romance short drama performance on WeChat in June" | Adjust promotion strategies and optimize content differentiation | | Trend Review | Content Director / Data Analyst | "Compare this month's and last month's short drama trend changes" | Master mid-to-long-term trends and guide content strategy planning | -
README.md 9.4 KB
# 短剧-公众号信息源 / playlet-wechat-feed --- ## 简介 短剧-公众号信息源是一款专为短剧创作者和内容运营打造的公众号爆款追踪工具。每日自动扫描公众号短剧内容,按阅读量筛选热门作品,智能聚类题材方向后生成可视化 HTML 日报与创作趋势分析。 **核心价值** - 🔥 发现当日公众号短剧爆款文章,精准定位高热度作品 - 📊 获取按题材智能聚类的热门内容,一目了然掌握热点分布 - 📈 分析爆款标题特征与创作趋势,挖掘流量密码 - 🔔 开启每日订阅,自动产出日报,建立情报体系 **适用对象** - ✍️ 短剧编剧 — 精准把握题材风口,提升选题命中率 - 📱 内容运营 — 每日追踪公众号短剧爆款,驱动内容决策 - 🏢 MCN 机构 — 监测行业动态,管理矩阵账号内容方向 - 📝 公众号号主 — 发现对标账号和爆款内容,优化创作策略 --- ## 功能特性 ### 核心功能 - **爆款发现** — 从公众号短剧文章中按阅读量筛选热门内容,精准定位高热度短剧作品 - **题材聚类** — 自动识别题材方向(穿越/霸总/重生/悬疑/甜宠/逆袭/年代/战神/古装),每日题材分类由内容动态决定 - **智能查询** — 默认查询全部短剧,数据不足时自动扩展题材批量查询,节省调用额度 - **自定义查询** — 支持指定任意题材、公众号、关键词定向查询,灵活覆盖任意短剧细分方向 - **创作洞察** — 分析爆款标题特征、题材趋势、公众号表现,深度挖掘创作规律 - **可视化日报** — 深色主题 HTML 日报,包含封面图、互动数据与文章直达链接 - **一键订阅** — 开启后每日自动产出日报,保存在本地文件夹 ### 特色亮点 - ⚡ **批量查询** — 所有题材通过批量接口一次性查询,高效节省接口调用次数 - 🧠 **智能聚类** — 9 大题材自动分类,每日动态调整,不固化 - 💾 **缓存机制** — 1 小时有效期,避免重复请求,快速查看近期结果 - 📅 **日期智能判断** — 自动检测目标日期有效性,避免无效调用 --- ## 密钥获取与安全说明 - 本技能需要使用环境变量:`REDFOX_API_KEY`。 - `REDFOX_API_KEY` 由 [红狐 hub](https://redfox.hk/settings/api-keys?source=github)(`https://redfox.hk`)提供。 - 请前往 [红狐 hub](https://redfox.hk?source=github) 注册账号,获取 `REDFOX_API_KEY`。 - 配置设备环境变量 `REDFOX_API_KEY` 后使用本技能。 - 在提供密钥前,请先确认密钥来源、可用范围、有效期及是否支持重置/撤销。 - 禁止在代码、提示词、日志或输出文件中硬编码/明文暴露密钥。 --- ## 使用指南 直接用自然语言描述需求,无需记忆命令。 ### 常用说法速查 | 意图 | 示例话术 | 效果 | |------|---------|------| | 查询最新日报 | "查询今天的短剧公众号日报" | 生成最新一期可视化日报 | | 按题材查询 | "穿越题材的短剧"、"查询霸总和甜宠的短剧" | 定向获取指定题材的爆款内容 | | 按时间查询 | "这个月的短剧趋势怎么样"、"6月的短剧爆款" | 分析一段时间内的内容趋势 | | 历史数据回顾 | "6月10号的短剧公众号日报有吗" | 查看指定日期的爆款数据 | | 组合查询 | "穿越题材6月短剧" | 精准定位特定题材+时间范围 | | 开启订阅 | "开启短剧日报每日订阅" | 每日自动产出并保存日报 | | 快速查看缓存 | "用缓存数据查看上次的短剧结果" | 1小时内免调用快速查看 | ### 输出示例 日报生成后,终端输出题材分类表格与创作趋势分析报告,同时生成深色主题 HTML 可视化日报并自动在浏览器中打开。HTML 日报包含: - 题材卡片布局,清晰展示各题材分布 - 每篇文章展示封面图、标题、公众号名称、阅读量、点赞数、评论数(各项为 0 时自动隐藏该字段) - 统计面板:题材数、文章数、平均阅读、总阅读 以下为 2026-06-15 真实输出样例: --- ## 短剧-公众号信息源 · 2026-06-15 日报 **扫描 176 篇热门短剧文章,聚类 6 个题材方向** --- ### 题材概览 | 题材 | 数量 | 占比 | 爆款亮点 | |------|------|------|---------| | #其他 | 156篇 | 88.6% | 《价值升维,短剧与明星双向奔赴的2.0时代》2.3w阅读,AI短剧工具类内容大量涌现 | | #甜宠 | 7篇 | 4.0% | 《热植物语》温馨睡前故事,均阅读800+,受众稳定 | | #霸总 | 6篇 | 3.4% | 克拉拉转型短剧演员引热议,单篇最高4905阅读 | | #悬疑 | 3篇 | 1.7% | 《短剧男演员去世真相》3801阅读,八卦向内容互动强 | | #穿越 | 3篇 | 1.7% | 陕西短剧基地千万实景遇冷,产业观察类内容受关注 | | #古装 | 1篇 | 0.6% | 《古装发型提示词,附图》1058阅读,AI创作辅助类单篇爆发 | --- ### 创作趋势分析 **一、新兴起量信号** - 🔥 **#古装** — 仅1篇但点赞率达3.6%(38赞/1058阅读),AI辅助创作类工具内容互动远超均值,提示词/工作流类内容有持续爆发潜力 - 🔥 **#悬疑** — 仅3篇但头部阅读达3801,八卦揭秘+短剧圈内幕的组合标题互动效率高于大盘均值 **二、爆款标题特征** | 特征模式 | 出现次数 | 典型案例 | 平均阅读 | |---------|---------|---------|---------| | 感叹号情绪钩子(!) | 93次 | 《OiiOii 2.0重磅升级,短剧带货真的要杀疯了...》 | 1374 | | 疑问号悬念钩子(?) | 55次 | 《长短剧边界消融,演员在千亿短剧新局有何机遇?》 | 1325 | | "N部"清单推荐体 | 13次 | 《5部高分上头短剧合集!霸总甜宠、都市治愈》 | 1072 | | AI+工具/平台名 | 15次 | 《全网7亿播放的AI短剧,背后的神级制作工具我找到了!》 | 约6500 | **三、核心公众号榜** 暂无核心公众号数据(本日接口未返回 accountName 字段) **四、题材趋势报告** **题材**:#甜宠 **作品数**:7篇 **平均阅读**:约900 **头部作品**:《热植物语》迪克羊仔(温馨甜宠睡前故事)— 1258阅读 **题材特征**:甜宠题材以"睡前故事""情头""宝藏剧推荐"为主要内容形态,标题普遍带有"甜""治愈""圆满"等情绪关键词,受众黏性高但流量天花板较低,阅读规模整体偏中腰部。 **创作建议**:可结合"CP向"二创内容、"甜宠+其他题材"复合标签(如甜宠×古装、甜宠×穿越)破圈,标题加入"闭眼追""宝藏""结局超甜"等完结承诺类钩子提升点击。 **五、#霸总** **题材**:#霸总 **作品数**:6篇 **平均阅读**:约2911 **头部作品**:《"亚洲第一美女"克拉拉,被豪门抛弃,转型当短剧演员!》— 4905阅读 **题材特征**:霸总题材本日热度主要由"明星入局短剧"的八卦新闻驱动,而非传统霸总剧情推荐。"豪门""转型""被抛弃"等反差词构成核心流量钩子,汉南拍摄地话题也带动了在地化传播。 **创作建议**:可借势明星/演员话题切入霸总题材,标题结构采用"身份反差+转折"公式(如"被XX抛弃,转型XX"),同时结合"高分合集""上头短剧"清单体做长尾流量。 **六、#悬疑** **题材**:#悬疑 **作品数**:3篇 **平均阅读**:约2047 **头部作品**:《短剧男演员去世真相,安以轩复出,侯明昊被拉出试水…》— 3801阅读 **题材特征**:悬疑题材本日以"圈内八卦+真相揭秘"形式呈现,标题普遍采用多个明星名串联+悬念问号的钩子结构;另有银发反诈AI微短剧(1718阅读)等政策向内容,整体数量少但单篇互动高于大盘均值。 **创作建议**:悬疑题材公众号端更适合"内幕揭秘""真相还原"等非虚构方向,标题可堆叠多个名人/事件名制造信息密度感,同时关注"反诈""社会议题"等政策风口,容易获得平台流量加持。 **七、跨题材对比建议** - **#霸总 × #甜宠** — 建议同步关注"霸总甜宠"复合标签的联动创作,本日《5部高分上头短剧合集!霸总甜宠、都市治愈》(2606阅读)已验证融合题材的合集形式有效,可进一步拆解两题材受众重叠度 - **#AI短剧(其他类内隐主题)× 全题材** — 本日38篇AI短剧相关内容均阅读2630,远超大盘1994均值,AI工具+任意题材的"制作教程/工具测评"方向是当前显著流量洼地,建议各题材创作者关注AI制作工作流内容 --- **日报地址**:`C:\Users\马祯\Downloads\QoderReports\短剧公众号日报_2026-06-15.html` > 数据说明:每日15:00更新昨天的数据 --- ## 使用场景 | 场景 | 角色 | 示例问法 | 收益 | |------|------|---------|------| | 选题调研 | 短剧编剧 | "最近什么短剧题材最火?帮我分析下穿越和重生" | 精准把握题材风口,提升选题命中率 | | 日报追踪 | 公众号运营 / MCN | "开启短剧日报订阅,每天帮我追踪公众号爆款" | 建立团队短剧情报体系,驱动内容决策 | | 竞品分析 | 品牌方 / 投放经理 | "查询霸总题材6月的短剧公众号表现" | 及时调整投放策略,优化内容差异化 | | 趋势复盘 | 内容总监 / 数据分析师 | "对比这个月和上个月的短剧趋势变化" | 掌握中长期趋势,指导内容战略规划 | -
SKILL.md 28.5 KB
--- name: playlet-wechat-feed description: "短剧-公众号信息源 — 每日扫描公众号短剧爆款文章,按阅读量筛选热门内容,智能聚类题材方向后生成包含封面图、互动数据与创作洞察的HTML日报。支持按题材(穿越/霸总/重生等)、公众号、时间范围定向查询。⚠️查询前脚本先做输入校验:关键词需命中短剧题材词库(topic_keywords 中规定的题材名+全部相关词,如「打脸」命中逆袭题材相关词),命中后直接使用该关键词查询数据;不满足时提醒'关键词不满足查询条件'并推荐相关词,且**不发起接口请求**;日期超出有效查询范围时提醒并自动回退最近有数据日期,无需用户确认。**无数据确认制**:查询无匹配数据或数据不足时禁止自动发起任何额外查询(禁止自动降级全量/自动扩展题材),必须先展示推荐题材关键词并等待用户确认后才可查询。当用户需要短剧公众号日报、公众号短剧爆款、短剧热点、短剧创作趋势或自定义题材查询时使用。" --- # 短剧-公众号信息源 ## 📝 简介 短剧-公众号信息源是一款专为短剧创作者和内容运营设计的公众号爆款追踪工具,每日自动扫描公众号短剧内容,按阅读量筛选热门作品,智能聚类题材方向后生成可视化 HTML 日报与创作趋势分析。 通过简单的指令,你可以: - 🔥 发现当日公众号短剧爆款文章 - 📊 获取按题材智能聚类的热门内容 - 📈 分析爆款标题特征与创作趋势 - 🔔 开启每日订阅,自动产出日报 适用于短剧编剧、内容运营、MCN 机构、公众号号主等需要追踪公众号短剧热点的场景。 > ⚠️ **重要提醒**:数据每日 15:00 更新前一天数据(实际可能延迟,以脚本真实探活为准)。查询前脚本先做输入校验:关键词需命中短剧题材词库(`topic_keywords` 中规定的**题材名+全部相关词**,如「打脸」命中逆袭题材相关词),**命中后直接使用该关键词查询数据**;不满足时提醒"关键词不满足查询条件"并推荐相关词,**不发起接口请求**;日期超出有效查询范围时提醒并自动回退最近有数据日期,无需用户确认。**无数据确认制(v2.3)**:查询无匹配数据或全量数据不足时,**禁止自动发起任何额外查询**(禁止自动降级全量、禁止自动扩展题材),必须先向用户展示推荐题材关键词并等待确认,确认后才可按推荐词重新查询。 ## ✨ 功能特性 ### 🎯 核心功能 | 功能模块 | 能力描述 | 核心价值 | |---------|---------|----------| | 爆款发现 | 从公众号短剧文章中按阅读量筛选热门内容 | 精准定位高热度短剧作品 | | 题材聚类 | 自动识别题材方向(穿越/霸总/重生/悬疑等) | 每天题材分类由内容动态决定 | | 智能查询 | 默认查询全部短剧;数据不足时提示推荐题材并询问用户,确认后才扩展查询 | 节省接口额度,不自动消耗额外查询 | | 自定义查询 | 用户可指定任意题材/公众号/关键词定向查询;无匹配数据时不自动查询,询问用户是否按推荐词重查 | 灵活覆盖任意短剧细分方向 | | 创作洞察 | 分析爆款标题特征、题材趋势、公众号表现 | 深度挖掘创作规律 | | 可视化日报 | 深色主题HTML,封面图+互动数据(为0时隐藏)+文章直链 | 直观展示每日短剧热点 | | 一键订阅 | `--subscribe` 开启每日自动产出 | 日报自动攒在本地文件夹 | ### ✨ 技术亮点 - ⚡ **探活式日期预检**:调用前先用轻量请求(无keyword, pageSize=1)真实探测目标日期是否有数据,替代纯本地时钟推断,自动拦截无效查询,避免浪费API额度 - 🧭 **前置输入校验**:查询前先判断用户的分类/关键词是否命中短剧题材词库(`topic_keywords` 中规定的**题材名+全部相关词**,命中后**直接使用该关键词查询数据**)、日期是否在有效查询范围;**不满足时提醒"关键词不满足查询条件"并推荐相关分类和关键词,不发起接口请求** - 🔄 **自动回退**:`--latest` 自动向前回退最多7天,找到最近有数据的日期再出日报 - 🛑 **无数据确认制**:查询无匹配数据 / 全量数据不足时,**不自动发起任何额外查询**(不自动降级全量、不自动扩展题材),输出推荐题材关键词并等待用户确认,确认后才重新查询 - 🧠 **智能聚类**:9 大题材自动分类(穿越/霸总/重生/悬疑/甜宠/逆袭/年代/战神/古装) - 🔒 **安全接入**:通过 API Key 鉴权,无需账号密码 - 💾 **缓存机制**:1 小时有效期,避免重复扣费 ## 🔑 安装配置 ### 前置条件 - Python 3 运行环境 - 红狐Hub API Key(前往 [红狐Hub 官网](https://redfox.hk?source=github) 注册获取,格式为 `ak_xxxxxxxx`) ### 环境变量配置 数据查询接口通过请求头 `X-API-KEY` 鉴权,Key 从环境变量 `REDFOX_API_KEY` 获取。 | 变量名 | 必填 | 说明 | |--------|------|------| | `REDFOX_API_KEY` | 是 | 红狐Hub API 访问密钥 | **配置方式**: - **macOS/Linux**:将 `export REDFOX_API_KEY=<值>` 追加到 `~/.zshrc` 或 `~/.bashrc`,然后 `source` 使其生效 - **Windows**:`[Environment]::SetEnvironmentVariable("REDFOX_API_KEY", "<值>", "User")`(需重启终端) - 配置后验证:`echo $REDFOX_API_KEY`(macOS/Linux)或 `echo %REDFOX_API_KEY%`(Windows) > 查询接口调用时通过 `source` 字段同步记录(值为 `短剧公众号信息源-GitHub`),无需额外请求保存接口。 ## 📖 使用指南 ### 基础使用 #### 1. 输入与日期预检(必须执行,先于任何接口调用) > ⛔ **核心规则:关键词/分类不满足短剧题材词库时,不发起任何接口请求** **数据更新规则**:每日 15:00 更新前一天的数据(实际可能延迟,以脚本真实探活为准) - 15:00 前:估算最新可用日期 = T-2(前天)——仅作初始起点 - 15:00 后:估算最新可用日期 = T-1(昨天)——仅作初始起点 **执行流程(每次查询前强制执行)**: 1. **关键词/分类前置校验**:判断用户输入的分类/关键词是否符合短剧题材词库 - 不满足时提醒"关键词不满足查询条件",推荐相关分类和关键词,**不发起接口请求**,直接停止并引导用户改用推荐词 - 混合词场景:保留有效关键词继续查询,无效关键词自动忽略并提示 - 全部无效:**不请求接口**,停止并推荐相关词 2. **日期前置校验**:判断目标日期格式是否有效、是否晚于今天;超出范围时提醒并推荐最近可用日期 3. **真实探活**:用 `pageSize=1` 不带 keyword 的轻量请求**实际探测**目标日期是否有数据,以接口返回为准(替代纯本地时钟推断) 4. **日期兜底**:目标日期未更新或超过查询时间范围时,自动向前回退获取最近时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动获取最近时间范围数据",无需用户确认 5. `--latest` 模式同样自动向前回退(最多7天)定位最近有数据的日期 6. **无数据确认制(v2.3)**:题材关键词查询无匹配数据 / 全量数据不足(<100条)时,**禁止自动发起任何额外查询**(禁止自动降级全量、禁止自动扩展题材),必须向用户展示推荐题材关键词并询问"是否按推荐题材重新查询",得到用户确认后才可发起查询 7. 若回退 7 天内均无数据,提示用户稍后再试或联系数据源确认更新状态 **示例对话**: ``` 用户:查询今天的短剧公众号日报 Agent:(执行 --latest,脚本自动向前回退定位最近有数据的日期,直接生成日报) 用户:查询"智能辅助驾驶"题材的短剧文章 Agent:⚠️ 关键词 ['智能辅助驾驶'] 不满足短剧查询条件(短剧按题材/剧情词匹配标题,非短剧题材词大概率无结果) 💡 推荐相关分类和关键词:穿越、霸总、重生、甜宠、悬疑、逆袭、年代、战神、古装、都市 🛑 关键词均不满足短剧查询条件,未发起任何接口请求。请使用推荐题材词重新查询。 用户:查询"古装"题材的短剧文章(该日期无匹配数据) Agent:📭 未查询到相关数据 [原因: 查询条件(题材词)在该日期无匹配作品] 🛑 未发起任何额外查询(禁止自动降级全量 / 自动扩展题材) 💡 推荐题材:穿越、霸总、重生、甜宠、悬疑、逆袭、年代、战神、古装、都市 ❓ 是否按推荐题材(如 穿越/霸总)重新查询?请确认后我再查询。 ``` #### 2. 生成爆款日报 ```bash # 生成最新一期日报(用户确认后,自动跳过无数据日期,不扣积分) python3 "$SKILL_PATH/assets/daily_report.py" --latest # 生成指定日期日报(历史日期已有数据,无需确认) python3 "$SKILL_PATH/assets/daily_report.py" --date 2026-06-10 # 自定义题材查询(用户指定方向;无匹配/数据不足时不自动扩展,询问用户确认后重查) python3 "$SKILL_PATH/assets/daily_report.py" --topics "穿越,霸总,重生,悬疑" --latest # 订阅 / 取消订阅 python3 "$SKILL_PATH/assets/daily_report.py" --subscribe python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe ``` > **查询策略**:默认查询全部短剧内容(pageSize=200)。**无数据确认制(v2.3)**:数据不足(小于100条)时**不再自动扩展题材**,脚本提示推荐题材(穿越→霸总→重生→悬疑→甜宠→逆袭)并等待用户确认,确认后才通过 `--topics` 重新查询;用户自定义题材时仅使用用户提供的列表。查询前自动探活目标日期;空结果自动重试1次。 #### 3. 创作趋势分析 日报生成后,**必须**基于聚类结果自动执行创作趋势分析: 1. 读取题材聚类结果,选取 TOP 5 热门题材 2. 分析每个题材的爆款数量、平均互动数据、头部作品特征 3. 识别新兴起量题材(数量少但互动高) 4. 输出结构化创作趋势报告 生成的 HTML 日报保存在 `~/Downloads/QoderReports/`,自动浏览器打开。终端同步输出题材分类表格 + 创作趋势分析报告。 ### 高级使用 #### 自定义题材查询 除默认短剧日报外,用户可指定任意题材组合进行定向查询: ```bash # 查询穿越题材热门短剧文章 python3 "$SKILL_PATH/assets/daily_report.py" --topics "穿越,时空,重生" # 查询霸总/甜宠题材 python3 "$SKILL_PATH/assets/daily_report.py" --topics "霸总,甜宠,总裁,虐恋" # 查询悬疑/反转题材 python3 "$SKILL_PATH/assets/daily_report.py" --topics "悬疑,推理,反转,惊悚" ``` **自定义查询逻辑**: - **前置校验(v2.2)**:查询前先判断关键词/分类是否符合短剧题材词库(穿越/霸总/重生/甜宠/悬疑/逆袭/年代/战神/古装等)。不满足时明确提醒"关键词不满足短剧查询条件",并**推荐相关分类和关键词**(优先从无效词中提取题材词,再补热门题材),且**不发起接口请求**,引导用户改用推荐词查询 - **无效词自动忽略**:混合词场景下保留有效关键词继续查询,无效关键词自动忽略并提示;全部无效时**不请求接口**,直接停止并推荐相关词 - **无数据确认制(v2.3)**:用户指定的关键词/题材无匹配数据时,**禁止自动降级为全量查询、禁止自动扩展题材**,脚本停止并输出推荐题材关键词,Agent 必须先询问用户"是否按推荐题材重新查询",得到确认后才可发起查询 - **数据不足确认制**:未指定题材的默认查询,全量数据不足(<100条)时同样不自动扩展题材,仅提示推荐题材并询问用户,已获取的数据仍正常生成日报 - 用户提供的所有题材通过批量接口一次性查询,无需逐个调用 - 查询结果自动去重,题材聚类、趋势分析均基于查询结果生成 #### 时间范围查询 ```bash # 查询 6 月短剧爆款 python3 "$SKILL_PATH/assets/daily_report.py" \ --start-time "2026-06-01 00:00:00" \ --end-time "2026-06-30 23:59:59" # 查询近 7 天短剧 python3 "$SKILL_PATH/assets/daily_report.py" \ --start-time "2026-06-10 00:00:00" \ --end-time "2026-06-17 23:59:59" ``` #### 订阅功能 ```bash # 开启每日订阅 — 日报自动产出并保存至 ~/Downloads/QoderReports/ python3 "$SKILL_PATH/assets/daily_report.py" --subscribe # 取消订阅 python3 "$SKILL_PATH/assets/daily_report.py" --unsubscribe ``` ### 命令速查 | 命令/参数 | 功能 | 默认值 | |----------|------|--------| | `--latest` | 自动向前回退最多7天,定位最近有数据的日期,跳过无数据区间 | — | | `--date YYYY-MM-DD` | 指定日期查询(未更新或超范围时自动回退最近有数据的日期) | 今天 | | `--topics "题材1,题材2"` | 自定义题材关键词,逗号分隔。查询前先校验是否符合短剧题材词库,不满足时提醒+推荐相关词并**不请求接口**;无匹配数据时不自动查询,询问用户确认后才重查 | `短剧` | | `--start-time` | 自定义开始时间 YYYY-MM-DD HH:MM:SS | — | | `--end-time` | 自定义结束时间 YYYY-MM-DD HH:MM:SS | — | | `--count N` | 扫描文章数量,满足即停 | `200` | | `--output-dir` | 输出目录 | `~/Downloads/QoderReports` | | `--api-key` | 指定 API Key(覆盖环境变量) | — | | `--subscribe` | 开启每日订阅 | — | | `--unsubscribe` | 关闭每日订阅 | — | ## 📊 输出格式(强制执行) > ⛔ **严格执行规则**: > - 以下模板是**唯一合法输出格式**,禁止任何自由发挥、省略、简化或重新组织 > - 禁止输出模板中未定义的额外内容(如"我来帮你…""以下是…"等口语化文字) > - 禁止合并、跳过任何板块,即使某板块数据为"暂无"也必须保留该板块标题 > - 日报生成后,对话回复**只能**包含以下内容,不得包含其他任何文字 每次运行日报后,对话输出**必须严格**按以下模板原样输出(仅替换 `{...}` 占位符): ``` ## 短剧-公众号信息源 · {日期} 日报 **扫描 {N} 篇热门短剧文章,聚类 {M} 个题材方向** --- ### 题材概览 | 题材 | 数量 | 占比 | 爆款亮点 | |------|------|------|---------| | #{题材名} | {N}篇 | {X}% | 《{头部作品标题}》{阅读数}阅读,{该题材当日内容特征简述} | | ... | ... | ... | ... | --- ### 创作趋势分析 **一、新兴起量信号** - 🔥 **#{题材}** — 仅{N}篇但{核心互动指标描述(如:均阅读X+、点赞率X%等)},{起量原因/内容特征分析} (若无新兴起量信号,输出:暂无新兴起量信号) > 新兴起量判断标准:作品数≤3篇但头部阅读超过大盘均值,或互动率(点赞/阅读)显著高于其他题材 **二、爆款标题特征** | 特征模式 | 出现次数 | 典型案例 | 平均阅读 | |---------|---------|---------|---------| | {标题结构特征描述(如:感叹号情绪钩子(!)、"N部"清单推荐体、AI+工具/平台名等)} | {N}次 | 《{标题}》 | {X} | | ... | ... | ... | ... | (若无标题数据,输出:暂无爆款标题数据) > 标题特征分析维度:标点符号使用(!/?/…)、数字清单体(N部/N条)、关键词类型(AI/明星/工具)、情绪钩子结构(反差词/悬念词/承诺词) **三、核心公众号榜** | 公众号 | 作品数 | 总阅读 | 代表作 | |--------|--------|--------|--------| | @{公众号} | {N}篇 | {X}w | 《{作品}》 | | ... | ... | ... | ... | (若无公众号数据,输出:暂无核心公众号数据(本日接口未返回 accountName 字段)) **四、题材趋势报告** **题材**:#{题材1} **作品数**:{N}篇 **平均阅读**:{X} **头部作品**:《{标题}》— {阅读}阅读 **题材特征**:{基于当日数据描述该题材的内容形态、标题特征、受众画像、流量天花板等} **创作建议**:{基于数据给出可执行的创作方向、标题公式、题材融合建议等} **五、#{题材2}** (同上格式) **六、#{题材3}** (同上格式) > 题材趋势报告选取 TOP 3 题材(排除"其他")逐一展开分析,每个题材必须包含「题材特征」和「创作建议」两个子模块 **七、跨题材对比建议** - **{题材A} × {题材B}** — {两题材的联动创作建议,基于当日数据中发现的跨题材信号} - **{主题线索(如:AI短剧)} × 全题材** — {当日数据中发现的跨题材共性趋势及创作机会} (若无建议,输出:暂无跨题材对比建议) --- **日报地址**:{HTML文件绝对路径} > 数据说明:每日15:00更新昨天的数据 ``` > 以上格式为**强制规范**,所有字段不可省略,板块标题(一、二、三、四、五、六、七)必须保留。若某模块无数据则在该板块内标注"暂无",不得删除板块本身。 **输出质量要求**: - 题材概览的「爆款亮点」必须包含该题材当日的内容特征简述,不能仅列出头部作品 - 爆款标题特征必须基于实际数据归纳,特征模式需具体可操作(如"感叹号情绪钩子"而非"情绪化标题") - 题材趋势报告的「题材特征」和「创作建议」必须基于当日数据,不能套用通用描述 - 跨题材对比建议必须从当日数据中发现真实联动信号,不能凭空推测 - HTML 日报中各项互动数据(阅读量 👁 / 点赞数 👍 / 评论数 💬)**为 0 时不展示该字段**,只展示有实际数据的指标 ## 🎯 使用场景 ### 场景一:短剧编剧选题调研 **角色**:短剧编剧 **需求**:了解当前公众号短剧哪些题材最火,为下一部作品选题 **使用方式**: 1. 运行默认日报,查看题材概览和趋势分析 2. 关注新兴起量信号,发现蓝海题材 3. 分析爆款标题特征,学习流量密码 **预期收益**:精准把握题材风口,提升选题命中率 --- ### 场景二:内容运营日报追踪 **角色**:公众号运营 / MCN 运营 **需求**:每日追踪短剧公众号爆款,形成团队内部情报 **使用方式**: 1. 开启 `--subscribe` 订阅,每日自动产出日报 2. 按题材查询(`--topics "穿越,霸总"`)聚焦团队关注方向 3. 分析核心公众号榜,发现优质对标账号 **预期收益**:建立团队短剧情报体系,驱动内容决策 --- ### 场景三:竞品分析 **角色**:品牌方 / 投放经理 **需求**:监测竞品公众号的短剧推广表现 **使用方式**: 1. 用 `--topics` 查询竞品相关关键词 2. 分析竞品题材分布和阅读数据 3. 对比自身与竞品的题材布局差异 **预期收益**:及时调整投放策略,优化内容差异化 --- ### 场景四:创作趋势复盘 **角色**:内容总监 / 数据分析师 **需求**:复盘一段时间内的短剧创作趋势变化 **使用方式**: 1. 使用 `--start-time` 和 `--end-time` 查询指定时间段 2. 对比不同日期的题材分布和爆款特征 3. 识别持续增长题材和衰退题材 **预期收益**:掌握中长期趋势,指导内容战略规划 ## 🏗️ 项目架构 ### 目录结构 ``` 短剧-公众号信息源/ ├── SKILL.md # 主文档(Skill 定义) ├── README.md # 快速开始指南 ├── assets/ │ └── daily_report.py # 主脚本 ├── scripts/ │ └── playlet_wechat_daily.py # 脚本副本 └── references/ ├── core_workflow.md # 核心执行流程、日期预检、输出格式模板、错误处理 └── examples.md # 使用示例与常见用法组合 ``` ### 技术栈 | 组件 | 技术 | 说明 | |------|------|------| | 运行环境 | Python 3 | 脚本语言 | | 数据源 | 红狐Hub API | 公众号短剧数据接口 | | 鉴权方式 | X-API-KEY | 请求头鉴权 | | 输出格式 | HTML/CSS | 深色主题可视化日报 | | 缓存机制 | JSON 文件 | 1 小时有效期 | ### 平台适配说明 本 skill 基于"短剧-抖音信息源"改造,针对公众号平台做了以下核心适配: | 维度 | 抖音版本 | 公众号版本(本 skill) | |------|---------|---------------------| | 平台标识 | `platform: 1` | `platform: 0` | | 核心指标 | 点赞量(likeCount) | 阅读量(readCount) | | 账号字段 | userName | accountName | | 展示指标 | 点赞、评论、分享 | 阅读(👁)、点赞(👍)、评论(💬),**为0时隐藏该字段** | | 主题色 | 粉色 #FB7299 | 绿色 #07C160 | | 图标 | 🔗👍⭐ | 👁👍💬 | | 文件命名 | 短剧抖音日报 | 短剧公众号日报 | | 缓存文件 | playlet_douyin_data.json | playlet_wechat_data.json | **核心代码差异**: ```python # 排序逻辑 — 公众号以阅读量为核心排序指标 # 抖音: unique_items.sort(key=lambda x: x.get("likeCount", 0), reverse=True) # 公众号: unique_items.sort(key=lambda x: x.get("readCount", 0), reverse=True) # 文件命名 # 抖音: f"短剧抖音日报_{date_str}.html" / "playlet_douyin_data.json" # 公众号: f"短剧公众号日报_{date_str}.html" / "playlet_wechat_data.json" ``` **保持一致的部分**:输入与日期预检机制(关键词不满足不请求接口)、无数据确认制(不自动降级/不自动扩展,询问后确认再查)、数据更新规则、题材聚类算法、去重机制、缓存机制、输出格式模板、订阅功能、创作趋势分析逻辑。 **注意事项**: 1. API 接口使用相同端点 `https://redfox.hk/story/api/parseWork/queryPlayletMsgs` 2. 必须设置 `platform: 0` 才能获取公众号数据 3. 公众号和抖音使用不同的缓存文件,互不干扰 ## ❓ 常见问答 ### 安装相关 **Q1: API Key 怎么获取?** A: 前往 [红狐Hub 官网](https://redfox.hk?source=github) 注册,登录后在个人中心获取,格式为 `ak_xxxxxxxx`。新注册用户获赠免费积分。 **Q2: 配置了 API Key 但提示无效?** A: 请检查: 1. Key 是否已正确复制(前后无空格) 2. Windows 下需重启终端使环境变量生效 3. 确认 Key 格式为 `ak_` 开头 ### 使用相关 **Q3: 为什么查询今天的数据提示无数据?** A: 数据每日 15:00 更新前一天数据(实际可能延迟,以脚本真实探活为准)。脚本会自动向前回退获取最近时间范围数据,并明确告知"当前查询时间未更新或超过查询时间范围,已为您自动获取最近时间范围数据",无需手动处理。 **Q4: 可以查询哪些题材?** A: 脚本内置 9 大题材分类:穿越、霸总、重生、悬疑、甜宠、逆袭、年代、战神、古装。你也可以通过 `--topics` 传入任意自定义关键词,但查询前会先校验关键词是否符合短剧题材词库,不满足时提醒+推荐相关词,**不请求接口**,避免浪费API额度。 **Q5: 默认查询和自定义题材查询有什么区别?** A: 默认查询全部短剧内容(pageSize=200),数据不足时提示推荐题材并询问用户,确认后才扩展查询;自定义查询仅使用你提供的题材列表,无匹配数据时不自动查询,询问用户是否按推荐词重查。 ### 故障排除 **Q6: 脚本报错 UnicodeEncodeError 怎么办?** A: Windows 下需设置环境变量 `PYTHONIOENCODING=utf-8`,可在命令前加上 `$env:PYTHONIOENCODING='utf-8';`。 **Q7: 接口返回错误码?** A: 常见错误码对照: | 错误码 | 含义 | 解决方式 | |--------|------|---------| | 1002 | 每页条数超过 200 | 脚本自动限制,无需处理 | | 3106 | 缺少 API Key | 配置 `REDFOX_API_KEY` 环境变量 | | 3107 | API Key 无效 | 检查 Key 格式和有效性 | | 3108 | 请求过于频繁 | 等待后重试 | | 3109 | 今日调用达上限 | 次日再试 | | 3201 | 积分不足 | 前往红狐Hub 充值 | ### 获取帮助 如有其他问题,可查看参考文档: - [core_workflow.md](references/core_workflow.md) — 核心执行流程、日期预检、输出格式模板、错误处理 - [examples.md](references/examples.md) — 使用示例与常见用法组合 ## 📋 真实输出示例(2026-06-15) > 以下为完整日报输出的真实样例,供 Agent 参考输出深度与格式规范。 ## 短剧-公众号信息源 · 2026-06-15 日报 **扫描 176 篇热门短剧文章,聚类 6 个题材方向** --- ### 题材概览 | 题材 | 数量 | 占比 | 爆款亮点 | |------|------|------|---------| | #其他 | 156篇 | 88.6% | 《价值升维,短剧与明星双向奔赴的2.0时代》2.3w阅读,AI短剧工具类内容大量涌现 | | #甜宠 | 7篇 | 4.0% | 《热植物语》温馨睡前故事,均阅读800+,受众稳定 | | #霸总 | 6篇 | 3.4% | 克拉拉转型短剧演员引热议,单篇最高4905阅读 | | #悬疑 | 3篇 | 1.7% | 《短剧男演员去世真相》3801阅读,八卦向内容互动强 | | #穿越 | 3篇 | 1.7% | 陕西短剧基地千万实景遇冷,产业观察类内容受关注 | | #古装 | 1篇 | 0.6% | 《古装发型提示词,附图》1058阅读,AI创作辅助类单篇爆发 | --- ### 创作趋势分析 **一、新兴起量信号** - 🔥 **#古装** — 仅1篇但点赞率达3.6%(38赞/1058阅读),AI辅助创作类工具内容互动远超均值,提示词/工作流类内容有持续爆发潜力 - 🔥 **#悬疑** — 仅3篇但头部阅读达3801,八卦揭秘+短剧圈内幕的组合标题互动效率高于大盘均值 **二、爆款标题特征** | 特征模式 | 出现次数 | 典型案例 | 平均阅读 | |---------|---------|---------|---------| | 感叹号情绪钩子(!) | 93次 | 《OiiOii 2.0重磅升级,短剧带货真的要杀疯了...》 | 1374 | | 疑问号悬念钩子(?) | 55次 | 《长短剧边界消融,演员在千亿短剧新局有何机遇?》 | 1325 | | "N部"清单推荐体 | 13次 | 《5部高分上头短剧合集!霸总甜宠、都市治愈》 | 1072 | | AI+工具/平台名 | 15次 | 《全网7亿播放的AI短剧,背后的神级制作工具我找到了!》 | 约6500 | **三、核心公众号榜** 暂无核心公众号数据(本日接口未返回 accountName 字段) **四、题材趋势报告** **题材**:#甜宠 **作品数**:7篇 **平均阅读**:约900 **头部作品**:《热植物语》迪克羊仔(温馨甜宠睡前故事)— 1258阅读 **题材特征**:甜宠题材以"睡前故事""情头""宝藏剧推荐"为主要内容形态,标题普遍带有"甜""治愈""圆满"等情绪关键词,受众黏性高但流量天花板较低,阅读规模整体偏中腰部。 **创作建议**:可结合"CP向"二创内容、"甜宠+其他题材"复合标签(如甜宠×古装、甜宠×穿越)破圈,标题加入"闭眼追""宝藏""结局超甜"等完结承诺类钩子提升点击。 **五、#霸总** **题材**:#霸总 **作品数**:6篇 **平均阅读**:约2911 **头部作品**:《"亚洲第一美女"克拉拉,被豪门抛弃,转型当短剧演员!》— 4905阅读 **题材特征**:霸总题材本日热度主要由"明星入局短剧"的八卦新闻驱动,而非传统霸总剧情推荐。"豪门""转型""被抛弃"等反差词构成核心流量钩子,汉南拍摄地话题也带动了在地化传播。 **创作建议**:可借势明星/演员话题切入霸总题材,标题结构采用"身份反差+转折"公式(如"被XX抛弃,转型XX"),同时结合"高分合集""上头短剧"清单体做长尾流量。 **六、#悬疑** **题材**:#悬疑 **作品数**:3篇 **平均阅读**:约2047 **头部作品**:《短剧男演员去世真相,安以轩复出,侯明昊被拉出试水…》— 3801阅读 **题材特征**:悬疑题材本日以"圈内八卦+真相揭秘"形式呈现,标题普遍采用多个明星名串联+悬念问号的钩子结构;另有银发反诈AI微短剧(1718阅读)等政策向内容,整体数量少但单篇互动高于大盘均值。 **创作建议**:悬疑题材公众号端更适合"内幕揭秘""真相还原"等非虚构方向,标题可堆叠多个名人/事件名制造信息密度感,同时关注"反诈""社会议题"等政策风口,容易获得平台流量加持。 **七、跨题材对比建议** - **#霸总 × #甜宠** — 建议同步关注"霸总甜宠"复合标签的联动创作,本日《5部高分上头短剧合集!霸总甜宠、都市治愈》(2606阅读)已验证融合题材的合集形式有效,可进一步拆解两题材受众重叠度 - **#AI短剧(其他类内隐主题)× 全题材** — 本日38篇AI短剧相关内容均阅读2630,远超大盘1994均值,AI工具+任意题材的"制作教程/工具测评"方向是当前显著流量洼地,建议各题材创作者关注AI制作工作流内容 --- **日报地址**:`C:\Users\马祯\Downloads\QoderReports\短剧公众号日报_2026-06-15.html` > 数据说明:每日15:00更新昨天的数据
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.