/** * 根据合并后的评论 JSON,生成「抓取回复最多的前 N 条评论的子回复」的云机脚本 * 用法: node gen_reply_crawl.js [topN] [perCommentLimit] */ const fs = require('fs'); const inFile = process.argv[2]; const outSh = process.argv[3]; const topN = parseInt(process.argv[4] || '30', 10); const perLimit = process.argv[5] || '0'; // 0=每条评论的回复抓全 const comments = JSON.parse(fs.readFileSync(inFile, 'utf8')); const cands = comments.filter(c => (c.replyCount || 0) > 0) .sort((a, b) => b.replyCount - a.replyCount) .slice(0, topN); console.log('候选(有回复)评论:', comments.filter(c => (c.replyCount || 0) > 0).length, '条'); console.log('本轮抓取前', cands.length, '条,声明回复合计', cands.reduce((s, c) => s + c.replyCount, 0), '条'); console.log('预计请求数 ≈', cands.reduce((s, c) => s + Math.ceil(c.replyCount / 50), 0), '页 →', Math.round(cands.reduce((s, c) => s + Math.ceil(c.replyCount / 50), 0) * 3.5 / 60), '分钟'); const lines = []; lines.push('#!/system/bin/sh'); lines.push('# 抓取指定评论的子回复(串行,含空页容错/断点续传)'); lines.push('# 由 gen_reply_crawl.js 自动生成 ' + new Date().toISOString()); lines.push('PX="http://127.0.0.1:2080"'); lines.push('VID="7552202593888603410"'); lines.push('DIR=/sdcard/Download/_replies'); lines.push('LOG=/sdcard/Download/_reply.log'); lines.push('PER=' + perLimit); lines.push('mkdir -p $DIR'); lines.push('echo "REPLY START $(date)" > $LOG'); lines.push(''); lines.push('grab() { # $1=comment_id $2=declared'); lines.push(' cid=$1; dec=$2; cursor=0; empty=0; got=0; pages=0'); lines.push(' cap=$((dec + 100))'); lines.push(' while [ $cursor -le $cap ]; do'); lines.push(' if [ "$PER" -gt 0 ] && [ $got -ge $PER ]; then break; fi'); lines.push(' pages=$((pages+1))'); lines.push(' f="$DIR/${cid}_$cursor.json"'); lines.push(' if [ -s "$f" ] && grep -q \'"code":0\' "$f"; then'); lines.push(' n=$(grep -o \'"video_id"\' "$f" | wc -l)'); lines.push(' got=$((got+n)); empty=0'); lines.push(' echo " cid=$cid cursor=$cursor SKIP n=$n" >> $LOG'); lines.push(' if [ $got -ge $dec ] && [ $n -lt 50 ]; then break; fi'); lines.push(' cursor=$((cursor+50)); continue'); lines.push(' fi'); lines.push(' a=1; n=0'); lines.push(' while [ $a -le 4 ]; do'); lines.push(' curl -s --compressed -m 40 -x "$PX" "https://www.tikwm.com/api/comment/reply?video_id=$VID&comment_id=$cid&count=50&cursor=$cursor" -o "$f"'); lines.push(' if grep -q \'"code":0\' "$f" 2>/dev/null; then'); lines.push(' n=$(grep -o \'"video_id"\' "$f" | wc -l); [ $n -gt 0 ] && break'); lines.push(' fi'); lines.push(' rm -f "$f"; a=$((a+1)); sleep 2'); lines.push(' done'); lines.push(' if [ $n -gt 0 ]; then'); lines.push(' got=$((got+n)); empty=0'); lines.push(' # 已达标 且 本页未满(末页) → 收工'); lines.push(' if [ $got -ge $dec ] && [ $n -lt 50 ]; then cursor=$((cursor+50)); break; fi'); lines.push(' else'); lines.push(' empty=$((empty+1))'); lines.push(' [ $empty -ge 5 ] && break'); lines.push(' fi'); lines.push(' cursor=$((cursor+50)); sleep 0.4'); lines.push(' done'); lines.push(' echo "REPLY cid=$cid 声明=$dec 实得=$got 页=$pages" >> $LOG'); lines.push('}'); lines.push(''); cands.forEach(c => { lines.push('grab ' + c.cid + ' ' + (c.replyCount || 0) + ' # ' + String(c.text || '').replace(/[\r\n]/g, ' ').slice(0, 40)); }); lines.push(''); lines.push('echo "REPLY DONE $(date)" >> $LOG'); lines.push('echo "DONE" > /sdcard/Download/_reply.done'); fs.writeFileSync(outSh, lines.join('\n'), 'utf8'); console.log('\n已生成:', outSh);