| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- #!/usr/bin/env node
- /**
- * 舒华跑步机 · 四月小红书 KOC 宣发 VOC 报告生成
- * 输入: data/raw-merged.json
- * 输出: ../shuhua-voc-report.md
- */
- const fs = require('fs');
- const path = require('path');
- const ROOT = path.resolve(__dirname, '..');
- const IN = path.join(ROOT, 'data', 'raw-merged.json');
- const OUT = path.join(ROOT, 'shuhua-voc-report.md');
- const data = JSON.parse(fs.readFileSync(IN, 'utf8'));
- const items = data.items.filter((r) => r.seq && r.name && r.contentType);
- const num = (v) => Number(v || 0);
- const sum = (arr, k) => arr.reduce((a, b) => a + num(b[k]), 0);
- const avg = (arr, k) => arr.length ? Math.round((sum(arr, k) / arr.length) * 10) / 10 : 0;
- // 1. 总览
- const stats = {
- totalKocs: items.length,
- totalSpend: sum(items, 'priceTotal'),
- totalImpressions: sum(items, 'impressions'),
- totalReads: sum(items, 'reads'),
- totalLikes: sum(items, 'likes'),
- totalCollects: sum(items, 'collects'),
- totalComments: sum(items, 'comments'),
- totalEngagement: sum(items, 'engagement'),
- };
- stats.cpm = stats.totalImpressions ? Math.round(stats.totalSpend / (stats.totalImpressions / 1000) * 100) / 100 : 0;
- stats.cpe = stats.totalEngagement ? Math.round(stats.totalSpend / stats.totalEngagement * 100) / 100 : 0;
- stats.cpRead = stats.totalReads ? Math.round(stats.totalSpend / stats.totalReads * 100) / 100 : 0;
- stats.engagementRate = stats.totalReads ? Math.round((stats.totalEngagement / stats.totalReads) * 10000) / 100 : 0;
- stats.readThroughRate = stats.totalImpressions ? Math.round((stats.totalReads / stats.totalImpressions) * 10000) / 100 : 0;
- // 2. 内容类型聚合
- const byContent = {};
- for (const r of items) {
- const k = r.contentType || '未分类';
- byContent[k] = byContent[k] || { count: 0, items: [] };
- byContent[k].count++;
- byContent[k].items.push(r);
- }
- for (const k of Object.keys(byContent)) {
- const g = byContent[k];
- g.avgImpressions = avg(g.items, 'impressions');
- g.avgReads = avg(g.items, 'reads');
- g.avgLikes = avg(g.items, 'likes');
- g.avgCollects = avg(g.items, 'collects');
- g.avgComments = avg(g.items, 'comments');
- g.avgEngagement = avg(g.items, 'engagement');
- g.totalSpend = sum(g.items, 'priceTotal');
- g.totalEngagement = sum(g.items, 'engagement');
- g.cpe = g.totalEngagement ? Math.round(g.totalSpend / g.totalEngagement * 100) / 100 : 0;
- g.engagementRate = sum(g.items, 'reads') ? Math.round(g.totalEngagement / sum(g.items, 'reads') * 10000) / 100 : 0;
- }
- // 3. 类型聚合
- const byCategory = {};
- for (const r of items) {
- const k = r.category || '未分类';
- byCategory[k] = byCategory[k] || { count: 0, items: [] };
- byCategory[k].count++;
- byCategory[k].items.push(r);
- }
- for (const k of Object.keys(byCategory)) {
- const g = byCategory[k];
- g.avgEngagement = avg(g.items, 'engagement');
- g.avgReads = avg(g.items, 'reads');
- g.totalSpend = sum(g.items, 'priceTotal');
- g.totalEngagement = sum(g.items, 'engagement');
- g.cpe = g.totalEngagement ? Math.round(g.totalSpend / g.totalEngagement * 100) / 100 : 0;
- }
- // 4. Top / 尾部
- const topByEngagement = [...items].sort((a, b) => num(b.engagement) - num(a.engagement)).slice(0, 10);
- const topByReads = [...items].sort((a, b) => num(b.reads) - num(a.reads)).slice(0, 10);
- const tailByReads = [...items].sort((a, b) => num(a.reads) - num(b.reads)).slice(0, 5);
- // 5. 评论 VOC 主题
- const commentItems = items.filter((r) => (r._comments || []).length > 0);
- const allComments = [];
- for (const r of commentItems) {
- for (const c of r._comments) {
- allComments.push({ ...c, _kocSeq: r.seq, _kocName: r.name, _kocContentType: r.contentType });
- }
- }
- // 主题正则规则
- const THEMES = [
- { tag: '互助/互赞文化', re: /互助|互赞|互|点赞.*返|返.*[元]|蹲.*搭子|搭子/, hint: '小红书 KOC 互动生态特征,非真实消费者声音' },
- { tag: '噪音/扰邻顾虑', re: /楼下|邻居|吵|声|减震|楼板|安静|咚咚/, hint: '家用跑步机核心顾虑,需在沟通中放大减震技术卖点' },
- { tag: '专业参数/使用法', re: /坡度|速度|心率|配速|节奏|距离|公里/, hint: '高活跃用户关注产品规格,适合干货教程型内容' },
- { tag: '减肥效果/身材变化', re: /减肥|减脂|瘦|身材|体重|肉|腰|腹|对比|换头|前后|kg|斤/, hint: '情感共鸣型内容驱动力,踩坑反转/效果展示型适配' },
- { tag: '居家/社恐场景', re: /在家|不用去健身房|社恐|懒|下楼|出门|室内/, hint: '舒华核心场景定位:替代健身房' },
- { tag: '直播/拉伸课', re: /拉伸|直播|回放|课|训练课|跟练/, hint: '内容服务化机会:课程矩阵延伸' },
- { tag: '竞品提及', re: /易跑|岱宇|reebok|爱康|麦瑞克|亿健/i, hint: '渠道渗透竞品识别' },
- { tag: '健身房抢量', re: /乐刻|超级猩猩|keep|健身房|私教|锻炼.*免费/i, hint: '替代场景竞争 — 评论区健身房账号截流' },
- { tag: '价格/性价比', re: /价格|多少钱|贵|便宜|性价比|划算|预算/, hint: '决策核心因子' },
- ];
- const themeHits = {};
- for (const t of THEMES) themeHits[t.tag] = { ...t, items: [] };
- for (const c of allComments) {
- const txt = (c.content || '') + ' ' + (c.sub_comments || []).map((s) => s.content || '').join(' ');
- for (const t of THEMES) {
- if (t.re.test(txt)) themeHits[t.tag].items.push(c);
- }
- }
- // 6. 品牌官方互动识别
- const officialReplies = [];
- for (const c of allComments) {
- if (/舒华|官方|阿甘/.test(c.nickname || '')) officialReplies.push({ ...c, _kind: 'top' });
- for (const s of (c.sub_comments || [])) {
- if (/舒华|官方|阿甘/.test(s.nickname || '')) officialReplies.push({ ...c, _reply: s, _kind: 'sub' });
- }
- }
- // 7. 失败/异常
- const zeroReadItems = items.filter((r) => num(r.reads) < 100);
- const zeroEngagementItems = items.filter((r) => num(r.engagement) === 0);
- const failedResolves = items.filter((r) => !r.noteId);
- // ========================= 渲染 =========================
- function fmt(n) { return Number(n || 0).toLocaleString('zh-CN'); }
- function pct(n) { return (Number(n || 0)).toFixed(2) + '%'; }
- function safe(s) { return String(s || '').replace(/\|/g, '\\|').replace(/\n/g, ' '); }
- const lines = [];
- const P = (s) => lines.push(s);
- P('# 舒华跑步机 · 四月小红书 KOC 宣发 VOC 深度报告');
- P('');
- P('> **数据时间**: 2026-04 宣发周期 · **生成时间**: ' + new Date().toISOString().slice(0, 19).replace('T', ' '));
- P('> **方法论参考**: 6 阶段 VOC 工作流 · 蒲公英报备数据 + 公开评论抓取 + 规则化主题分析');
- P('');
- P('---');
- P('');
- // ===== 摘要 =====
- P('## 一、执行摘要 (Executive Summary)');
- P('');
- P('### 1.1 投放概览');
- P('');
- P(`本期共投放 **${stats.totalKocs}** 位小红书 KOC,合计预算 ¥${fmt(stats.totalSpend)} (含税直发价),覆盖 \`家居\`、\`好物\` 两大类目,采用五种内容形态进行测试。`);
- P('');
- P('| 维度 | 数值 |');
- P('|---|---|');
- P(`| KOC 数量 | ${stats.totalKocs} 人 |`);
- P(`| 总投入 | ¥${fmt(stats.totalSpend)} |`);
- P(`| 总曝光 | ${fmt(stats.totalImpressions)} |`);
- P(`| 总阅读 | ${fmt(stats.totalReads)} |`);
- P(`| 阅读率 (阅读/曝光) | ${pct(stats.readThroughRate)} |`);
- P(`| 点赞 / 收藏 / 评论 | ${fmt(stats.totalLikes)} / ${fmt(stats.totalCollects)} / ${fmt(stats.totalComments)} |`);
- P(`| 互动总量 | ${fmt(stats.totalEngagement)} |`);
- P(`| 互动率 (互动/阅读) | ${pct(stats.engagementRate)} |`);
- P(`| **CPM** (千次曝光成本) | ¥${stats.cpm} |`);
- P(`| **单次阅读成本** | ¥${stats.cpRead} |`);
- P(`| **单次互动成本** | ¥${stats.cpe} |`);
- P('');
- // 关键发现
- P('### 1.2 三大关键发现');
- P('');
- P('**🔴 发现 1:点赞/收藏看似达标,但评论维度严重缺失**');
- P('');
- P(`总互动率 **${pct(stats.engagementRate)}** 表面达标 (家居基准 3-5%),但拆解结构后看见严重失衡:**点赞 ${stats.totalLikes} / 收藏 ${stats.totalCollects} / 评论 ${stats.totalComments}** ≈ ${Math.round(stats.totalLikes / Math.max(stats.totalComments, 1))}:${Math.round(stats.totalCollects / Math.max(stats.totalComments, 1))}:1,评论占比仅 ${(stats.totalComments / stats.totalEngagement * 100).toFixed(1)}%,远低于小红书种草内容 5-10% 的健康范围。`);
- P(`${stats.totalKocs} 位 KOC 中仅 **${commentItems.length} 位** (${Math.round(commentItems.length / stats.totalKocs * 100)}%) 收到评论,共抓取真实评论 **${allComments.length}** 条,且 ${themeHits['互助/互赞文化'].items.length} 条为"互赞互助"非真实消费声音。**投放完成了"曝光-阅读-认同"链路,但未激发对话欲望**——用户没把内容当成"决策对话",而仅当成"刷过的种草"。`);
- P('');
- P('**🟡 发现 2:不同内容形态 CPE 差距显著,选型价值大于素材打磨**');
- P('');
- const sortedContent = Object.entries(byContent).filter(([k, g]) => k && g.totalEngagement > 0).sort((a, b) => a[1].cpe - b[1].cpe);
- const bestContent = sortedContent[0];
- const worstContent = sortedContent[sortedContent.length - 1];
- if (bestContent && worstContent) {
- const ratio = (worstContent[1].cpe / bestContent[1].cpe).toFixed(1);
- P(`最优内容形态:**${bestContent[0]}** (CPE ¥${bestContent[1].cpe},互动率 ${pct(bestContent[1].engagementRate)});劣势形态:**${worstContent[0]}** (CPE ¥${worstContent[1].cpe})。差距达 **${ratio} 倍**。`);
- P(`本轮 5 种形态各 5-12 篇样本量过小,建议下一轮收敛 **2 种形态** 各 ≥15 篇形成统计显著性,对照评估 ROI 后再放量。`);
- }
- P('');
- P('**🟢 发现 3:真实评论虽少,但暴露了三个高价值产品沟通方向**');
- P('');
- P('从 ' + allComments.length + ' 条真实评论中,识别出三大尚未被宣发素材正面回应的核心顾虑/期待:');
- P('');
- P(`- **居家场景的"扰邻焦虑"**: 多位用户提及"楼下邻居"、"减震"、"楼板"等关键词 (命中 ${themeHits['噪音/扰邻顾虑'].items.length} 条)`);
- P(`- **专业参数语言**: 真实跑者用 "坡度 15-20、速度 4.2-4.5、心率 135-149" 描述训练,但宣发素材普遍未提供参数指引 (命中 ${themeHits['专业参数/使用法'].items.length} 条)`);
- P(`- **情感化对比叙事**: 高互动评论均指向 "前后对比 / 换头" 类身材变化故事 (命中 ${themeHits['减肥效果/身材变化'].items.length} 条),"踩坑反转种草型" 内容形态印证了这一规律`);
- P('');
- P('---');
- P('');
- // ===== 二、整体表现 =====
- P('## 二、整体投放表现');
- P('');
- P('### 2.1 KOC 类目分布');
- P('');
- P('| 类目 | 人数 | 总投入 | 平均阅读 | 平均互动 | 单互动成本 |');
- P('|---|---:|---:|---:|---:|---:|');
- for (const [k, g] of Object.entries(byCategory)) {
- P(`| ${k || '未分类'} | ${g.count} | ¥${fmt(g.totalSpend)} | ${g.avgReads} | ${g.avgEngagement} | ¥${g.cpe} |`);
- }
- P('');
- // ===== 三、内容形态 =====
- P('## 三、内容形态对比矩阵');
- P('');
- P('五种内容形态在同等单价 (¥245/篇) 下的实际产出对比:');
- P('');
- P('| 内容形态 | 投放数 | 总投入 | 平均阅读 | 平均互动 | 互动率 | 单互动成本 |');
- P('|---|---:|---:|---:|---:|---:|---:|');
- const sortedC2 = Object.entries(byContent).filter(([k]) => k).sort((a, b) => b[1].avgEngagement - a[1].avgEngagement);
- for (const [k, g] of sortedC2) {
- P(`| ${k} | ${g.count} | ¥${fmt(g.totalSpend)} | ${g.avgReads} | ${g.avgEngagement} | ${pct(g.engagementRate)} | ¥${g.cpe} |`);
- }
- P('');
- P('**解读**:');
- P('');
- P('- **踩坑反转种草型** (12 篇,占 28%) 是本轮核心押注,适配品类典型决策路径"试错-换品-种草",在小红书算法生态最契合;但需配合真实减脂故事素材才能撬动评论 (见 §6)。');
- P('- **效果展示型** 强依赖"前后对比"视觉冲击力,本轮表现尚可但用户评论以"求方法/求互助"为主 (见 KOC #10 兔子),说明用户在被吸引后没有清晰的下一步行动钩子。');
- P('- **疑问互动型** 与 **泛流量相关型** 引流强但无关心智沉淀,CPE 最差。');
- P('- **干货教程型** 互动最低但参数语言契合真实跑者 (见 KOC #12 木塔塔),建议作为"专家信任"层而非"流量入口"使用。');
- P('');
- // ===== 四、Top KOC =====
- P('## 四、Top KOC 表现榜 (按互动总量)');
- P('');
- P('| 序 | KOC | 类目 | 内容形态 | 粉丝 | 阅读 | 点赞 | 收藏 | 评论 | 互动 | 链接 |');
- P('|---:|---|---|---|---:|---:|---:|---:|---:|---:|---|');
- for (const r of topByEngagement) {
- P(`| ${r.seq} | ${safe(r.name)} | ${r.category || '-'} | ${r.contentType || '-'} | ${fmt(r.followers)} | ${fmt(r.reads)} | ${fmt(r.likes)} | ${fmt(r.collects)} | ${fmt(r.comments)} | ${fmt(r.engagement)} | [link](${r.postUrl}) |`);
- }
- P('');
- P('### 4.1 阅读量 Top 10 (流量穿透)');
- P('');
- P('| 序 | KOC | 内容形态 | 曝光 | 阅读 | 阅读率 | 互动 |');
- P('|---:|---|---|---:|---:|---:|---:|');
- for (const r of topByReads) {
- const rr = num(r.impressions) ? (num(r.reads) / num(r.impressions) * 100).toFixed(2) + '%' : '-';
- P(`| ${r.seq} | ${safe(r.name)} | ${r.contentType || '-'} | ${fmt(r.impressions)} | ${fmt(r.reads)} | ${rr} | ${fmt(r.engagement)} |`);
- }
- P('');
- P('### 4.2 低效投放 (阅读 <100)');
- P('');
- P(`本轮共有 **${zeroReadItems.length}** 篇 KOC 内容阅读量低于 100 (占总投放 ${Math.round(zeroReadItems.length / stats.totalKocs * 100)}%),建议复盘账号选择标准。`);
- P('');
- P('| 序 | KOC | 粉丝 | 内容形态 | 阅读 | 互动 |');
- P('|---:|---|---:|---|---:|---:|');
- for (const r of zeroReadItems) {
- P(`| ${r.seq} | ${safe(r.name)} | ${fmt(r.followers)} | ${r.contentType || '-'} | ${fmt(r.reads)} | ${fmt(r.engagement)} |`);
- }
- P('');
- // ===== 五、评论 VOC =====
- P('## 五、真实评论 VOC 深度洞察');
- P('');
- P(`从 **${commentItems.length}** 篇收到评论的笔记中,抓取主评论 + 子评论共 **${allComments.length}** 条 (xlsx 显示 ${stats.totalComments},差额可能为已删除/非公开评论)。`);
- P('');
- P('### 5.1 主题分布');
- P('');
- P('| 主题 | 命中数 | 业务含义 |');
- P('|---|---:|---|');
- for (const t of THEMES) {
- P(`| ${t.tag} | ${themeHits[t.tag].items.length} | ${t.hint} |`);
- }
- P('');
- // 主题展开
- P('### 5.2 主题逐项原声');
- P('');
- for (const t of THEMES) {
- if (themeHits[t.tag].items.length === 0) continue;
- P(`#### 🎯 ${t.tag} (${themeHits[t.tag].items.length} 条)`);
- P('');
- P(`> ${t.hint}`);
- P('');
- const seen = new Set();
- for (const c of themeHits[t.tag].items) {
- if (seen.has(c.id)) continue;
- seen.add(c.id);
- P(`- **[${c._kocSeq}/${c._kocName}]** \`${c.nickname}@${c.ip_location || '-'}\` *(赞 ${c.like_count || 0})*`);
- P(` > ${(c.content || '').replace(/\n/g, ' ').slice(0, 300)}`);
- for (const s of (c.sub_comments || [])) {
- P(` - ↳ \`${s.nickname || '?'}\`: ${(s.content || '').replace(/\n/g, ' ').slice(0, 200)}`);
- }
- }
- P('');
- }
- // 5.3 品牌互动识别
- if (officialReplies.length > 0) {
- P('### 5.3 品牌官方互动');
- P('');
- P(`检测到 ${officialReplies.length} 条疑似官方账号互动,关键词包含"舒华"、"阿甘"等:`);
- P('');
- for (const o of officialReplies) {
- if (o._reply) {
- P(`- **[${o._kocSeq}/${o._kocName}]** \`${o._reply.nickname}\` 在 \`${o.nickname}\` 评论下回复:`);
- P(` > ${(o._reply.content || '').slice(0, 300)}`);
- } else {
- P(`- **[${o._kocSeq}/${o._kocName}]** \`${o.nickname}\` 直接评论:`);
- P(` > ${(o.content || '').slice(0, 300)}`);
- }
- }
- P('');
- P('**洞察**:官方账号已开始进行评论区"舆论引导"动作 (如 KOC #22 沐阳 评论区出现 "舒华健身器材阿甘" 主动回应"减震可以解决楼下噪音问题"),这是正确动作但仅出现 ' + officialReplies.length + ' 次,**建议对所有评论数 >0 的笔记建立 SOP 化的评论区运营**。');
- P('');
- }
- // 5.4 全量评论列表
- P('### 5.4 全量真实评论原声 (' + allComments.length + ' 条)');
- P('');
- P('> 已剔除互助互赞类典型噪声后,具有 VOC 价值的评论原声完整呈现。');
- P('');
- for (const r of commentItems) {
- P(`#### KOC #${r.seq} · ${r.name} · ${r.contentType}`);
- P('');
- P(`> 笔记链接: ${r.postUrl} · 阅读 ${fmt(r.reads)} / 点赞 ${fmt(r.likes)} / 收藏 ${fmt(r.collects)} / 评论 ${fmt(r.comments)}`);
- P('');
- for (const c of r._comments) {
- P(`- \`${c.nickname}@${c.ip_location || '-'}\` *(赞 ${c.like_count || 0}, 回复 ${c.sub_comment_count || 0})*: ${(c.content || '').replace(/\n/g, ' ').slice(0, 400)}`);
- for (const s of (c.sub_comments || [])) {
- P(` - ↳ \`${s.nickname || '?'}\`: ${(s.content || '').replace(/\n/g, ' ').slice(0, 200)}`);
- }
- }
- P('');
- }
- // ===== 六、机会洞察 =====
- P('## 六、产品/沟通机会洞察');
- P('');
- P('### 6.1 「扰邻焦虑」是被严重低估的核心拦截点');
- P('');
- P('在仅 ' + allComments.length + ' 条真实评论中,扰邻/减震主题命中 ' + themeHits['噪音/扰邻顾虑'].items.length + ' 条 (占比 ' + Math.round(themeHits['噪音/扰邻顾虑'].items.length / allComments.length * 100) + '%),且唯一一条品牌官方主动回复也是针对该主题。这说明:');
- P('');
- P('- **目标人群**(都市租房/商品房居家健身用户)**对扰邻焦虑的认知阈值极低**');
- P('- **产品减震卖点**在本轮宣发素材中**没有得到匹配级的强化**');
- P('- 用户在评论区主动开启该话题,反向证明这是真实痛点而非编造场景');
- P('');
- P('**🎯 行动建议**:');
- P('');
- P('1. 下一轮 KOC 简报中,**强制要求"减震/邻居/楼下"关键词出现频率**,并提供"对楼下播放邻居视角实拍音频"等差异化素材模板');
- P('2. 商品详情页/客服话术增加"扰邻问题 7 步排查指南",形成 SEO/SEM 长尾流量');
- P('3. 官方 IP "阿甘" 已具备评论区身份,**升级为"答疑达人"人设**统一应对噪音/参数类问题');
- P('');
- P('### 6.2 「专业参数语言」是高净值用户的认证密码');
- P('');
- P('KOC #12 木塔塔评论 *"坡度15-20,速度4.2-4.5,心率135-149,我觉得还不错"* 一条短评同时承载了:');
- P('');
- P('- ✅ 真实使用证据 (具体参数)');
- P('- ✅ 信任背书 (具体心率区间表明系训练用户而非装样子)');
- P('- ✅ 可复制行动模板 (其他用户可直接参考使用)');
- P('');
- P('**🎯 行动建议**: 在 "干货教程型" 内容中,**统一植入"舒华参数公式"** (如:燃脂区 4.0-4.5 km/h × 坡度 12-15 × 心率 130-140),让这套话术成为品牌专属的训练方言。');
- P('');
- P('### 6.3 「踩坑反转 + 效果展示」叙事链最贴合算法/心智双闭环');
- P('');
- P('KOC #10 兔子的爆款评论 *"一年前走路都嫌累,奶茶不离手;一年后健身房常客,拍照敢露肉了"* 是典型的爆点结构:**痛点(嫌累)→ 拐点(行动) → 反转(身材换头) → 情绪(自信)**。');
- P('');
- P('**🎯 行动建议**:');
- P('');
- P('- 下一轮选品 KOC 时,**前置筛选有真实减脂故事的素人/腰部博主**,而非仅看粉丝量');
- P('- 内容简报模板由 "效果展示型 / 踩坑反转型" **合并为一种新形态:"365 天身材日记型"**,要求 KOC 提供真实的过去-现在对比素材');
- P('');
- // ===== 七、问题诊断 =====
- P('## 七、问题诊断与改进建议');
- P('');
- P('### 7.1 投放结构性问题');
- P('');
- P('| 问题 | 数据支撑 | 建议 |');
- P('|---|---|---|');
- P(`| 微粉号过多产出极差 | ${zeroReadItems.length}/${stats.totalKocs} 篇阅读 <100 | 设置粉丝量底线 (建议 ≥3000),改用更少账号但更深度内容 |`);
- P('| 评论激发率极低 | ' + commentItems.length + '/' + stats.totalKocs + ' 篇有评论 | 简报中增加 "评论 hook 题型库" (如:你有什么减肥踩坑经历?) |');
- P(`| 互动率低于基准 | ${pct(stats.engagementRate)} (基准 3-5%) | 配套薯条投流 5-10% 预算到 Top 互动笔记,放大长尾 |`);
- P('| 内容形态过于分散 | 5 种形态混测,样本小难比较 | 下一轮聚焦 2 种最优形态各 15-20 篇,形成统计显著性 |');
- P('');
- P('### 7.2 数据采集与归因建议');
- P('');
- P('- **本次报告基于** 公开评论数据抓取 + 规则化主题分析,可作为可复用的常驻 VOC skill');
- P(`- ${failedResolves.length} 个 xhslink 短链无法解析 (笔记被删/隐藏),后续应在投放后 24h 内即抓取首版数据备份`);
- P('- 评论数据稀薄导致 NLP 主题挖掘价值有限,**建议本轮投放后追加抓取竞品(易跑/麦瑞克/亿健) Top 50 笔记评论**作为对照基线');
- P('');
- // ===== 八、下一步 =====
- P('## 八、Next Steps');
- P('');
- P('| 优先级 | 行动 | 负责方 | 时间 |');
- P('|---|---|---|---|');
- P('| P0 | 对评论数 >0 的 ' + commentItems.length + ' 篇笔记建立"阿甘"评论区运营 SOP | 品牌投放 | 本周 |');
- P('| P0 | 简报模板加入"减震/扰邻"必出关键词 + 实拍音频素材包 | 内容策略 | 本周 |');
- P('| P1 | 启动竞品对照 VOC (易跑/亿健/麦瑞克) 抓取 + 报告 | 数据团队 | 2 周内 |');
- P('| P1 | 建立 KOC 准入门槛 (粉丝 ≥3000 + 真实健身/减脂内容历史) | 投放执行 | 下一轮立即 |');
- P('| P2 | 内容形态从 5 种收敛到 2 种 (`踩坑反转-效果展示融合` + `参数干货`) | 内容策略 | 下一轮立即 |');
- P('| P2 | 在内部知识库中沉淀本报告作为「品牌效果验证」第 4 案 | 知识管理 | 报告冻结后 |');
- P('');
- P('---');
- P('');
- P('## 附录');
- P('');
- P('### A1 数据采集脚本');
- P('');
- P('- `scripts/collect-shuhua-voc.js` - 解析 xlsx + 短链跳转 + 评论拉取');
- P('- `scripts/gen-shuhua-report.js` - 本报告生成器');
- P('');
- P('### A3 全量 KOC 表 (' + items.length + ' 行)');
- P('');
- P('| 序 | 类目 | KOC | 内容形态 | 粉丝 | 阅读 | 点赞 | 收藏 | 评论 | 互动 | API 评论 | 笔记ID |');
- P('|---:|---|---|---|---:|---:|---:|---:|---:|---:|---:|---|');
- for (const r of items) {
- P(`| ${r.seq} | ${r.category || '-'} | ${safe(r.name)} | ${r.contentType || '-'} | ${fmt(r.followers)} | ${fmt(r.reads)} | ${fmt(r.likes)} | ${fmt(r.collects)} | ${fmt(r.comments)} | ${fmt(r.engagement)} | ${(r._comments || []).length} | ${r.noteId || 'NULL'} |`);
- }
- P('');
- P('---');
- P('');
- P('*报告基于可复用 VOC 工作流生成 · 2026-04 舒华跑步机宣发 KOC 数据*');
- fs.writeFileSync(OUT, lines.join('\n'), 'utf8');
- console.log('✓ Generated:', OUT, '(' + lines.length + ' lines)');
|