feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
Deploy VitePress site to Pages / build (push) Canceled after 0s
Deploy VitePress site to Pages / Deploy (push) Canceled after 0s

移植自 mac-agent-os 的 mediacrawler_adapter:不起子进程、不开页面,用浏览器里那份
登录态直接调抖音 Web 接口。产物键名照抄 store/douyin,所以 ingest 那条链路一个字不用改。

**目前能用的(真环境实测,非推断)**:

    profile/other : 200, 7075 字节  —— 博主主页指标(粉丝/获赞/作品数/昵称)
    aweme/detail  : 200, 45425 字节 —— 单条作品详情(含点赞/评论/收藏/分享)

**目前不能用的:作品列表 `aweme/post`。** 两个互相独立的原因:
  1. 这个接口被抖音单独升级成了真校验:不带 x-tt-argus 回 403「Uifid Not Found」,
     带上 dummy 值回 200 + **空 body**。也就是说「头在不在」骗得过,「真校验」过不了。
     同一套头打 profile/other 和 aweme/detail 都是通的 —— 抖音是挑着接口加保护的,
     挑中的恰好是「批量拉作品列表」这个最敏感的动作。
  2. 改走页面截获也不行:CDP 浏览器打开博主主页会落到「验证码中间页」(当天大量探测的
     代价,过几小时要重测)。

  所以现在的边界是:**已知作品的指标刷新能做,自动发现新作品做不了**。

**排查中控住变量后得到的两条事实**(都写进注释了):
  · `Accept` / `Accept-Language` / `Referer` 才是主页接口能返回真数据的原因 —— 只有
    UA+client hints+Cookie 时是 200 但仅 121 字节的空壳,补上这三个头变 7074 字节。
    (我先前猜的 sec-ch-ua 不是关键。)
  · 因此 UA 与 client hints 必须**成套地取自同一个浏览器**,所以 BrowserIdentity 一次
    从 CDP 取齐 cookie + UA + hints,而不是各自写死。

「200 + 空 body 必须当场报错」也是刻意写死的:放过去它会在下游变成「这个博主没作品」,
把一次失败伪装成一条正常结果 —— 爬虫那条路正是这么栽的,还被翻译成「账号被封」。

测试 +11:cookie 解析、请求头成套性(含 uifid 缺失/回退)、产物键名与 store 对齐、
以及 _get 的三条失败路径(空 body / 403 带网关原话 / 正常返回)。
This commit is contained in:
2026-10-10 17:12:25 +08:00
parent 21ff01b894
commit 2112c1a870
1601 changed files with 367425 additions and 0 deletions
@@ -0,0 +1,113 @@
#!/bin/bash
# chrome_debug.sh — 启动 Chrome 远程调试(供 launchd 调用)
# 确保 Chrome 以 --remote-debugging-port=9222 运行
#
# v2 — 增强版
# - 所有日志带时间戳
# - 重启次数限制(最多 5 次,超出后退出等待手动处理)
# - 重启间隔递增(5s → 15s → 30s)
# - 检测到 OOM 时打印内存状态
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
USER_DATA_DIR="/tmp/chrome-douyin-profile"
PIDFILE="/tmp/chrome-debug.pid"
LOG_FILE="/tmp/chrome_debug_launchd.log"
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a /tmp/chrome_debug_watch.log
}
is_9222_alive() {
curl -s --connect-timeout 3 http://127.0.0.1:9222/json/version >/dev/null 2>&1
}
launch_chrome() {
nohup "$CHROME" \
--remote-debugging-port=9222 \
--user-data-dir="$USER_DATA_DIR" \
--no-first-run --no-default-browser-check \
--disable-features=ChromeWhatsNewUI \
--window-position=9999,9999 \
about:blank \
> "$LOG_FILE" 2>&1 &
echo $! > "$PIDFILE"
log "Chrome 已启动 (PID $!),屏幕外位置 (9999,9999)"
}
# ── 主流程 ──
log "=== chrome_debug.sh 启动 ==="
# 先检查 9222 是否已经在线
if is_9222_alive; then
log "端口 9222 已有 Chrome 在监听,进入健康检查循环"
else
log "端口 9222 无响应,启动 Chrome..."
launch_chrome
# 等最多 15 秒
for i in $(seq 1 15); do
sleep 1
if is_9222_alive; then
log "Chrome debug 启动成功(第 ${i} 秒)"
break
fi
done
if ! is_9222_alive; then
log "❌ Chrome 启动超时(15 秒),请检查: cat $LOG_FILE"
exit 1
fi
fi
# ── 健康检查循环 ──
RESTART_COUNT=0
MAX_RESTARTS=5
while true; do
sleep 10
if is_9222_alive; then
# 正常:端末还在,继续监控
continue
fi
# 端口 9222 挂了
RESTART_COUNT=$((RESTART_COUNT + 1))
log "⚠️ 端口 9222 无响应(第 ${RESTART_COUNT} 次)"
if [ "$RESTART_COUNT" -gt "$MAX_RESTARTS" ]; then
log "❌ 已连续重启 ${MAX_RESTARTS} 次失败,退出等待手动处理"
log " 请检查: 系统内存是否充足(vm_stat),或手动启动 Chrome"
log " 手动命令: pkill -f 'remote-debugging-port=9222'"
log " $CHROME --remote-debugging-port=9222 --user-data-dir=$USER_DATA_DIR --no-first-run --no-default-browser-check about:blank &"
exit 2
fi
# 递增等待时间:5s → 15s → 30s → 30s → 30s
WAIT=$(( RESTART_COUNT <= 1 ? 5 : RESTART_COUNT == 2 ? 15 : 30 ))
log "等待 ${WAIT} 秒后重启..."
# 清理残留 Chrome 进程(防止多实例)
pkill -f "remote-debugging-port=9222" 2>/dev/null || true
sleep 2
# 打印内存状态帮助排查
memory_free=$(vm_stat | awk '/free/ {print $3}' | sed 's/\.//')
log "当前空闲内存页: ${memory_free:-?}"
launch_chrome
# 等最多 20 秒看有没有起来
for i in $(seq 1 20); do
sleep 1
if is_9222_alive; then
log "Chrome 重启成功(第 ${i} 秒)"
# 成功一次重置计数
RESTART_COUNT=0
break
fi
done
if ! is_9222_alive; then
log "❌ Chrome 重启失败(20 秒超时),继续下一轮"
fi
done