|
|
@@ -29,17 +29,19 @@ type PlaywrightCookie = {
|
|
|
|
|
|
type MetricKind =
|
|
|
| 'playCount'
|
|
|
+ | 'exposureCount'
|
|
|
| 'likeCount'
|
|
|
| 'commentCount'
|
|
|
| 'shareCount'
|
|
|
| 'collectCount'
|
|
|
| 'fansIncrease'
|
|
|
+ | 'worksCount'
|
|
|
| 'coverClickRate'
|
|
|
| 'avgWatchDuration'
|
|
|
| 'totalWatchDuration'
|
|
|
| 'completionRate';
|
|
|
|
|
|
-type ExportMode = 'watch' | 'interaction' | 'fans';
|
|
|
+type ExportMode = 'watch' | 'interaction' | 'fans' | 'publish';
|
|
|
|
|
|
function ensureDir(p: string) {
|
|
|
return fs.mkdir(p, { recursive: true });
|
|
|
@@ -97,6 +99,7 @@ function detectMetricKind(sheetName: string): MetricKind | null {
|
|
|
const n = sheetName.trim();
|
|
|
// 观看数据:子表命名可能是「观看趋势」或「观看数趋势」
|
|
|
if (n.includes('观看趋势') || n.includes('观看数')) return 'playCount';
|
|
|
+ if (n.includes('曝光趋势')) return 'exposureCount';
|
|
|
if (n.includes('封面点击率')) return 'coverClickRate';
|
|
|
if (n.includes('平均观看时长')) return 'avgWatchDuration';
|
|
|
if (n.includes('观看总时长')) return 'totalWatchDuration';
|
|
|
@@ -110,6 +113,9 @@ function detectMetricKind(sheetName: string): MetricKind | null {
|
|
|
|
|
|
// 涨粉数据(只取净涨粉趋势)
|
|
|
if (n.includes('净涨粉') && n.includes('趋势')) return 'fansIncrease';
|
|
|
+
|
|
|
+ // 发布数据:总发布趋势 → 每日发布数,入库 works_count
|
|
|
+ if (n.includes('总发布趋势')) return 'worksCount';
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
@@ -210,9 +216,10 @@ export function parseXhsExcel(
|
|
|
// 按导出类型过滤不相关子表,避免误写字段
|
|
|
if (
|
|
|
(mode === 'watch' &&
|
|
|
- !['playCount', 'coverClickRate', 'avgWatchDuration', 'totalWatchDuration', 'completionRate'].includes(kind)) ||
|
|
|
+ !['playCount', 'exposureCount', 'coverClickRate', 'avgWatchDuration', 'totalWatchDuration', 'completionRate'].includes(kind)) ||
|
|
|
(mode === 'interaction' && !['likeCount', 'commentCount', 'shareCount', 'collectCount'].includes(kind)) ||
|
|
|
- (mode === 'fans' && kind !== 'fansIncrease')
|
|
|
+ (mode === 'fans' && kind !== 'fansIncrease') ||
|
|
|
+ (mode === 'publish' && kind !== 'worksCount')
|
|
|
) {
|
|
|
continue;
|
|
|
}
|
|
|
@@ -236,11 +243,13 @@ export function parseXhsExcel(
|
|
|
if (!result.has(key)) result.set(key, { recordDate: d });
|
|
|
const obj = result.get(key)!;
|
|
|
|
|
|
- if (kind === 'playCount' || kind === 'likeCount' || kind === 'commentCount' || kind === 'shareCount' || kind === 'collectCount' || kind === 'fansIncrease') {
|
|
|
+ if (kind === 'playCount' || kind === 'exposureCount' || kind === 'likeCount' || kind === 'commentCount' || kind === 'shareCount' || kind === 'collectCount' || kind === 'fansIncrease' || kind === 'worksCount') {
|
|
|
const n = parseChineseNumberLike(valueVal);
|
|
|
if (typeof n === 'number') {
|
|
|
if (kind === 'playCount') obj.playCount = n;
|
|
|
+ if (kind === 'exposureCount') obj.exposureCount = n;
|
|
|
if (kind === 'likeCount') obj.likeCount = n;
|
|
|
+ if (kind === 'worksCount') obj.worksCount = n;
|
|
|
if (kind === 'commentCount') obj.commentCount = n;
|
|
|
if (kind === 'shareCount') obj.shareCount = n;
|
|
|
if (kind === 'collectCount') obj.collectCount = n;
|
|
|
@@ -433,7 +442,7 @@ export class XiaohongshuAccountOverviewImportService {
|
|
|
await page.getByText('账号概览', { exact: true }).first().click().catch(() => undefined);
|
|
|
await page.getByText('笔记数据', { exact: true }).first().click();
|
|
|
|
|
|
- const exportAndImport = async (tabText: '观看数据' | '互动数据' | '涨粉数据', mode: ExportMode) => {
|
|
|
+ const exportAndImport = async (tabText: '观看数据' | '互动数据' | '涨粉数据' | '发布数据', mode: ExportMode) => {
|
|
|
await page.getByText(tabText, { exact: true }).first().click();
|
|
|
await page.getByText(/近\d+日/).first().click().catch(() => undefined);
|
|
|
await page.getByText('近30日', { exact: true }).click();
|
|
|
@@ -496,7 +505,10 @@ export class XiaohongshuAccountOverviewImportService {
|
|
|
// 3) 涨粉数据:只取“净涨粉趋势”(解析器已过滤)
|
|
|
await exportAndImport('涨粉数据', 'fans');
|
|
|
|
|
|
- // 4) 粉丝数据页:打开粉丝数据、点击近30天,解析 overall_new 接口,将每日粉丝总数写入 user_day_statistics.fans_count
|
|
|
+ // 4) 发布数据:近30日导出,解析「总发布趋势」→ user_day_statistics.works_count
|
|
|
+ await exportAndImport('发布数据', 'publish');
|
|
|
+
|
|
|
+ // 5) 粉丝数据页:打开粉丝数据、点击近30天,解析 overall_new 接口,将每日粉丝总数写入 user_day_statistics.fans_count
|
|
|
await this.importFansDataTrendFromPage(context, page, account);
|
|
|
|
|
|
logger.info(`[XHS Import] Account all tabs done. accountId=${account.id}`);
|