collect-douyin-only.js 3.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. #!/usr/bin/env node
  2. /**
  3. * 只跑抖音板块 · 把结果合并到已有 data/jiangzhong-*-voc.json
  4. * 用法:node scripts/tools/collect-douyin-only.js [liver|probiotic|monkey|all]
  5. */
  6. const fs = require('fs');
  7. const path = require('path');
  8. const { collectDouyinForProduct, loadCookie, COOKIE_PATH } = require('./collect-douyin');
  9. // ⚠ douyin_share_urls 按「官方号 + 品牌竞品号 + 垂类博主号」三卡顺序填写
  10. // 填空的项会被 normalizeAccountSpecs 过滤掉
  11. const PRODUCTS = [
  12. {
  13. id: 'liver',
  14. name: '江中肝纯片',
  15. keywords_cn: ['肝纯片', '江中肝纯片', '护肝片'],
  16. douyin_share_url: 'https://v.douyin.com/BMklXPTyiUM/', // 向下兼容
  17. douyin_share_urls: [
  18. { share_url: 'https://v.douyin.com/BMklXPTyiUM/', role: '官方号', label: '江中(现绑)' },
  19. // { share_url: '___待填___', role: '品牌竞品', label: '葵花护肝片 / 葵花药业' },
  20. // { share_url: '___待填___', role: '垂类博主', label: '肝病科医生 / 护肝博主' },
  21. ],
  22. },
  23. {
  24. id: 'probiotic',
  25. name: '儿童乳酸菌素片',
  26. keywords_cn: ['儿童乳酸菌素片', '江中乳酸菌', '儿童肠胃调理'],
  27. douyin_share_url: 'https://v.douyin.com/1eV76OP0FNM/',
  28. douyin_share_urls: [
  29. { share_url: 'https://v.douyin.com/1eV76OP0FNM/', role: '官方号', label: '江中食疗(现绑)' },
  30. // { share_url: '___待填___', role: '品牌竞品', label: '妈咪爱 / 亿活 / 合生元' },
  31. // { share_url: '___待填___', role: '垂类博主', label: '儿科医生 / 育儿达人' },
  32. ],
  33. },
  34. {
  35. id: 'monkey',
  36. name: '江中猴菇饮',
  37. keywords_cn: ['猴菇饮', '江中猴菇饮', '养胃饮品'],
  38. douyin_share_url: 'https://v.douyin.com/C3mMbhRYKHw/',
  39. douyin_share_urls: [
  40. { share_url: 'https://v.douyin.com/C3mMbhRYKHw/', role: '官方号', label: '江中制药(现绑)' },
  41. // { share_url: '___待填___', role: '品牌竞品', label: '康恩贝 / 太阳神 / 三九' },
  42. // { share_url: '___待填___', role: '垂类博主', label: '胃肠科医生 / 养胃博主' },
  43. ],
  44. },
  45. ];
  46. async function main() {
  47. const target = process.argv[2] || 'all';
  48. const picks = target === 'all' ? PRODUCTS : PRODUCTS.filter((p) => p.id === target);
  49. if (!picks.length) {
  50. console.error(`❌ 未知 product: ${target}`);
  51. process.exit(1);
  52. }
  53. const cookie = loadCookie();
  54. if (!cookie) {
  55. console.error(`❌ ${COOKIE_PATH} 未找到`);
  56. process.exit(1);
  57. }
  58. console.log(`🍪 cookie loaded: ${cookie.length} chars`);
  59. for (const p of picks) {
  60. const jsonPath = path.resolve(__dirname, '..', '..', 'data', `jiangzhong-${p.id}-voc.json`);
  61. if (!fs.existsSync(jsonPath)) {
  62. console.error(`❌ ${jsonPath} 不存在,请先跑全量采集`);
  63. continue;
  64. }
  65. console.log(`\n━━━━ [${p.id}] ${p.name} ━━━━`);
  66. const t0 = Date.now();
  67. const dy = await collectDouyinForProduct(p, cookie);
  68. const elapsed = ((Date.now() - t0) / 1000).toFixed(1);
  69. const data = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
  70. data.douyin = dy;
  71. data._meta = data._meta || {};
  72. data._meta.douyin_updated_at = new Date().toISOString();
  73. fs.writeFileSync(jsonPath, JSON.stringify(data, null, 2));
  74. console.log(`✅ [${p.id}] 完成 (${elapsed}s) → video=${dy.video ? 'YES' : 'NO'} comments=${dy.comments.length} posts=${dy.user_posts.length} searches=${Object.keys(dy.searches).length}`);
  75. }
  76. }
  77. main().catch((e) => { console.error(e); process.exit(1); });