84 lines
3.3 KiB
JavaScript
84 lines
3.3 KiB
JavaScript
// 分析 57 条视频:按题材分类、排序、算效率
|
|||
|
|
import fs from 'node:fs';
|
||
|
|
|
||
|
|
const vids = JSON.parse(fs.readFileSync('out/videos.json', 'utf8'));
|
||
|
|
const rows = vids.map(v => ({
|
||
|
|
id: v.id || v.article_id,
|
||
|
|
title: v.title || '',
|
||
|
|
date: (v.publish_time || v.publish_at || '').slice(0, 10),
|
||
|
|
view: Number(v.view_count || 0),
|
||
|
|
like: Number(v.likes_count || 0),
|
||
|
|
comment: Number(v.comment_count || 0),
|
||
|
|
share: Number(v.share_count || 0),
|
||
|
|
collect: Number(v.collect_count || 0),
|
||
|
|
rec: Number(v.rec_count || 0),
|
||
|
|
}));
|
||
|
|
|
||
|
|
// 题材分类
|
||
|
|
function cat(t) {
|
||
|
|
if (/大角羊|雪羊|盘羊|羱羊|岩羊|山羊/.test(t)) return 'A1 羊类(高山)';
|
||
|
|
if (/野牦牛|牦牛/.test(t)) return 'A2 牦牛';
|
||
|
|
if (/雪兔|驯鹿|驼鹿|麋鹿/.test(t)) return 'A3 其他蹄类';
|
||
|
|
if (/母鸡|公鸡|小鸡|大鹅|鹅|土狗|狗|猫|狐狸|黄鼠狼|老鹰|鹰/.test(t)) return 'B 农家院';
|
||
|
|
if (/河马|鳄鱼|穿山甲|豪猪|水牛|野猪|犀牛|斑马|长颈鹿|大象|狮子|猎豹|花豹|美洲狮|雪豹|老虎|蜜獾|狼/.test(t)) return 'C 猛兽对抗';
|
||
|
|
if (/企鹅|海豹|水獭|北极熊|北极狐|海豚|鲸/.test(t)) return 'D 极地/水生';
|
||
|
|
return 'E 其他';
|
||
|
|
}
|
||
|
|
|
||
|
|
for (const r of rows) r.cat = cat(r.title);
|
||
|
|
|
||
|
|
const lines = [];
|
||
|
|
const p = s => lines.push(s);
|
||
|
|
|
||
|
|
p(`总视频数: ${rows.length}`);
|
||
|
|
const totalView = rows.reduce((a, r) => a + r.view, 0);
|
||
|
|
p(`总阅读: ${totalView}`);
|
||
|
|
p('');
|
||
|
|
|
||
|
|
p('=== 按题材汇总 ===');
|
||
|
|
const byCat = {};
|
||
|
|
for (const r of rows) {
|
||
|
|
const c = byCat[r.cat] ||= { n: 0, view: 0, like: 0, comment: 0, share: 0, best: 0 };
|
||
|
|
c.n++; c.view += r.view; c.like += r.like; c.comment += r.comment; c.share += r.share;
|
||
|
|
c.best = Math.max(c.best, r.view);
|
||
|
|
}
|
||
|
|
const catRows = Object.entries(byCat).map(([k, c]) => ({ cat: k, n: c.n, view: c.view, avg: Math.round(c.view / c.n), like: c.like, comment: c.comment, share: c.share, best: c.best }))
|
||
|
|
.sort((a, b) => b.avg - a.avg);
|
||
|
|
p(['题材', '条数', '总阅读', '条均', '总点赞', '总评论', '总分享', '最高'].join('\t'));
|
||
|
|
for (const c of catRows) p([c.cat, c.n, c.view, c.avg, c.like, c.comment, c.share, c.best].join('\t'));
|
||
|
|
|
||
|
|
p('');
|
||
|
|
p('=== TOP 15 单条 ===');
|
||
|
|
p(['日期', '阅读', '点赞', '评论', '分享', '题材', '标题'].join('\t'));
|
||
|
|
for (const r of [...rows].sort((a, b) => b.view - a.view).slice(0, 15)) {
|
||
|
|
p([r.date, r.view, r.like, r.comment, r.share, r.cat, r.title.slice(0, 45)].join('\t'));
|
||
|
|
}
|
||
|
|
|
||
|
|
p('');
|
||
|
|
p('=== BOTTOM 10 单条 ===');
|
||
|
|
for (const r of [...rows].sort((a, b) => a.view - b.view).slice(0, 10)) {
|
||
|
|
p([r.date, r.view, r.like, r.comment, r.cat, r.title.slice(0, 45)].join('\t'));
|
||
|
|
}
|
||
|
|
|
||
|
|
p('');
|
||
|
|
p('=== 每日发布 vs 阅读 ===');
|
||
|
|
const byDate = {};
|
||
|
|
for (const r of rows) {
|
||
|
|
const d = byDate[r.date] ||= { n: 0, view: 0 };
|
||
|
|
d.n++; d.view += r.view;
|
||
|
|
}
|
||
|
|
for (const d of Object.keys(byDate).sort()) {
|
||
|
|
const x = byDate[d];
|
||
|
|
p([d, x.n, x.view, x.n ? Math.round(x.view / x.n) : 0].join('\t'));
|
||
|
|
}
|
||
|
|
|
||
|
|
p('');
|
||
|
|
p('=== 标题含违规词 ===');
|
||
|
|
const banned = ['实拍', '抓拍', '监控拍', '彻底绝望', '陷入绝望', '最高境界'];
|
||
|
|
const hits = rows.filter(r => banned.some(b => r.title.includes(b)));
|
||
|
|
p('命中条数: ' + hits.length);
|
||
|
|
for (const r of hits) p(` ${r.view}\t${r.title.slice(0, 50)}`);
|
||
|
|
|
||
|
|
fs.writeFileSync('out/analysis-report.txt', lines.join('\n'), 'utf8');
|
||
|
|
fs.writeFileSync('out/rows.json', JSON.stringify(rows, null, 2), 'utf8');
|
||
|
|
console.log('done');
|