feat(monitor): 抖音 Web 接口客户端 —— 绕开爬虫子进程,直接发 HTTP
移植自 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:
@@ -0,0 +1,92 @@
|
||||
{
|
||||
"id": "douyin_active_v1",
|
||||
"name": "抖音-高活跃养号",
|
||||
"version": "2.0",
|
||||
"platform": "douyin",
|
||||
"description": "多浏览+点赞+收藏+50%评论率+2次@random搜索+搜索结果浏览",
|
||||
"steps": [
|
||||
{"step_id": 1, "op": "goto_home", "args": {}},
|
||||
{"step_id": 2, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 3, "op": "like", "args": {}},
|
||||
{"step_id": 4, "op": "next_video", "args": {}},
|
||||
{"step_id": 5, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 6, "op": "like", "args": {}},
|
||||
{"step_id": 7, "op": "collect", "args": {}},
|
||||
{"step_id": 8, "op": "next_video", "args": {}},
|
||||
{"step_id": 9, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 10, "op": "like", "args": {}},
|
||||
{"step_id": 11, "op": "next_video", "args": {}},
|
||||
{"step_id": 12, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 13, "op": "like", "args": {}},
|
||||
{"step_id": 14, "op": "collect", "args": {}},
|
||||
{"step_id": 15, "op": "next_video", "args": {}},
|
||||
{"step_id": 16, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 17, "op": "like", "args": {}},
|
||||
|
||||
{"step_id": 18, "op": "search", "args": {"keyword": "@random"}},
|
||||
{"step_id": 19, "op": "open_video", "args": {}},
|
||||
{"step_id": 20, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 21, "op": "like", "args": {}},
|
||||
{"step_id": 22, "op": "collect", "args": {}},
|
||||
{"step_id": 23, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 24, "op": "open_video", "args": {}},
|
||||
{"step_id": 25, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 26, "op": "like", "args": {}},
|
||||
{"step_id": 27, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 28, "op": "open_video", "args": {}},
|
||||
{"step_id": 29, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 30, "op": "like", "args": {}},
|
||||
{"step_id": 31, "op": "collect", "args": {}},
|
||||
{"step_id": 32, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 33, "op": "open_video", "args": {}},
|
||||
{"step_id": 34, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 35, "op": "like", "args": {}},
|
||||
{"step_id": 36, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 37, "op": "open_video", "args": {}},
|
||||
{"step_id": 38, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 39, "op": "like", "args": {}},
|
||||
{"step_id": 40, "op": "collect", "args": {}},
|
||||
{"step_id": 41, "op": "open_comments","args": {}},
|
||||
{"step_id": 42, "op": "post_comment", "args": {"text": "@corpus"}},
|
||||
{"step_id": 43, "op": "close_comments","args": {}},
|
||||
|
||||
{"step_id": 44, "op": "search", "args": {"keyword": "@random"}},
|
||||
{"step_id": 45, "op": "open_video", "args": {}},
|
||||
{"step_id": 46, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 47, "op": "like", "args": {}},
|
||||
{"step_id": 48, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 49, "op": "open_video", "args": {}},
|
||||
{"step_id": 50, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 51, "op": "like", "args": {}},
|
||||
{"step_id": 52, "op": "collect", "args": {}},
|
||||
{"step_id": 53, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 54, "op": "open_video", "args": {}},
|
||||
{"step_id": 55, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 56, "op": "like", "args": {}},
|
||||
{"step_id": 57, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 58, "op": "open_video", "args": {}},
|
||||
{"step_id": 59, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 60, "op": "like", "args": {}},
|
||||
{"step_id": 61, "op": "collect", "args": {}},
|
||||
{"step_id": 62, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 63, "op": "open_video", "args": {}},
|
||||
{"step_id": 64, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 65, "op": "like", "args": {}},
|
||||
{"step_id": 66, "op": "scroll_feed", "args": {}},
|
||||
{"step_id": 67, "op": "open_video", "args": {}},
|
||||
{"step_id": 68, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 69, "op": "like", "args": {}},
|
||||
{"step_id": 70, "op": "collect", "args": {}},
|
||||
{"step_id": 71, "op": "open_comments","args": {}},
|
||||
{"step_id": 72, "op": "post_comment", "args": {"text": "@corpus"}},
|
||||
{"step_id": 73, "op": "close_comments","args": {}},
|
||||
|
||||
{"step_id": 74, "op": "goto_home", "args": {}},
|
||||
{"step_id": 75, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 76, "op": "like", "args": {}},
|
||||
{"step_id": 77, "op": "next_video", "args": {}},
|
||||
{"step_id": 78, "op": "wait_watch", "args": {"seconds": null}},
|
||||
{"step_id": 79, "op": "like", "args": {}},
|
||||
{"step_id": 80, "op": "collect", "args": {}}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user