移植自 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 带网关原话 / 正常返回)。
4.5 KiB
4.5 KiB
AgentOS Matrix 反检测技术方案 v1.0.0
最后更新:2026-05-01 基于旧版完整手册 + 当前系统现状分析
一、当前系统缺失的反检测措施
| 层级 | 缺失项 | 风险 | 旧版实施方案 |
|---|---|---|---|
| 浏览器层 | CDP调试标记 (--remote-debugging-port) |
🔴 高 | 已修复:改 Playwright 原生启动 |
| 浏览器层 | navigator.webdriver 未覆写 |
🔴 高 | CDP注入 Object.defineProperty(navigator, 'webdriver', {get:()=>false}) |
| 浏览器层 | navigator.platform 与 UA 不一致 |
🟠 中 | 覆写为 Linux armv8l (Android) 或 iPad |
| 浏览器层 | navigator.standalone 未覆写 |
🟠 中 | 强制返回 false |
| 浏览器层 | 触摸事件模拟 | 🟠 中 | Emulation.setTouchEmulationOverride |
| 行为层 | 无随机动作延迟 | 🔴 高 | action_delay: [200, 5000]ms 随机延迟 |
| 行为层 | 无行为画像配置 | 🟠 中 | 每小时点赞上限、评论上限、每日总量 |
| 行为层 | 无观看时长随机化 | 🟠 中 | view_duration: [5000, 60000]ms |
| 行为层 | 无打字速度模拟 | 🟠 中 | typing_speed: [50, 200]ms/char |
| 网络层 | 无独立IP代理 | 🔴 高 | 静态住宅IP + socks5 代理 |
| 网络层 | 无账号熔断机制 | 🟠 中 | 连续失败3次自动冷却30分钟 |
| DOM层 | App跳转拦截未完整 | 🟠 中 | 已实现 Fetch 拦截 |
| DOM层 | 弹窗清理选择器不全 | 🟠 中 | 需要扩展覆盖更多弹窗类型 |
| 操作层 | 搜索后跳转到 so.douyin.com |
🟠 中 | 已修复:用首页搜索栏 |
二、浏览器启动配置(已修复)
# ✅ 正确:不使用 --remote-debugging-port
# ✅ 正确:在 launch_persistent_context 中设置平板参数
ctx = await pw.chromium.launch_persistent_context(
user_data_dir=profile,
channel="chrome",
headless=False,
viewport={"width": 702, "height": 783},
device_scale_factor=2,
is_mobile=True,
has_touch=True,
user_agent="Mozilla/5.0 (iPad; CPU OS 16_0 like Mac OS X)...",
locale="zh-CN",
args=["--no-first-run", "--no-default-browser-check"],
)
三、需要新增的反检测措施
3.1 浏览器指纹覆写
async def apply_fingerprint_protection(page):
"""覆写浏览器指纹特征"""
await page.evaluate("""() => {
// 隐藏自动化标记
Object.defineProperty(navigator, 'webdriver', { get: () => false });
// 平台一致性
Object.defineProperty(navigator, 'platform', { get: () => 'iPad' });
// 隐藏PWA能力
Object.defineProperty(navigator, 'standalone', { get: () => false });
// 修改插件检测
Object.defineProperty(navigator, 'plugins', {
get: () => [1, 2, 3, 4, 5]
});
// 修改语言
Object.defineProperty(navigator, 'languages', { get: () => ['zh-CN', 'zh'] });
}""")
3.2 拟人化行为参数
BEHAVIOR_PROFILE = {
"douyin_01": {
"action_delay": [0.5, 3.0], # 动作间隔秒
"view_duration": [5, 60], # 浏览停留秒
"typing_speed": [50, 200], # 打字 ms/字符
"max_likes_per_hour": 15,
"max_comments_per_hour": 3,
"max_collects_per_hour": 5,
"active_hours": [8, 23],
"max_daily_actions": 150,
}
}
3.3 账号熔断器
class CircuitBreaker:
def __init__(self, account_id):
self.failures = 0
self.max_failures = 3
self.cooldown = 1800 # 30分钟
3.4 IP代理配置
需要为每个账号配置独立静态住宅 IP(当前未配置)。
四、实施优先级
| 优先级 | 措施 | 预估工时 |
|---|---|---|
| P0 | 浏览器指纹覆写 (webdriver/platform/standalone) | 30分钟 |
| P0 | 随机动作延迟 (action_delay) | 30分钟 |
| P1 | 行为画像配置 (每小时上限/每日上限) | 30分钟 |
| P1 | 弹窗清理扩展 | 15分钟 |
| P1 | 账号熔断器 | 30分钟 |
| P2 | IP代理接入 | 需要外部采购 |
| P2 | 多浏览器内核轮换 | 后续阶段 |
五、与旧版对比总结
旧版完整方案包含:隐身容器 (Colima+Docker) → 反检测浏览器 (Camoufox/Patchright) → 移动端伪装 → 拟人化行为 → IP代理 → 熔断机制
当前系统只实现了基础的浏览器控制和页面交互,反检测层几乎全部缺失。 需要在后续迭代中逐步补齐。