- SKILL.md 瘦身重写(核心层+按需加载references/) - Checklist: CHECK-3/4(session)删除,五项→三项 - 新增6个references子文档(path-a/path-b/phase-details/experience-rules-full/mcp-tool-reference/common-pitfalls) - 删除 references/domain-session-guide.md - 工具引用对齐实际MCP(32工具),verify_signer_offline替代verify_against_session - cases/_template.md 新增可验证事实清单段 - 经验法则session相关条目改写 - 红线四条、第一原则0-5、三分法、四板斧、六步法完整保留
11 KiB
经验法则完整版(30 条)
说明:SKILL.md 核心层保留了前 10 条最常用的。本文档是完整的 30 条
版本:v3.1.0(MCP v0.9.0 工具名迁移)
来源:v3.0.0 从 46 条压缩合并而来,基于三次真实站点(瑞数/TikTok/抖音)实战数据
一、识别与选择(5 条)
规则 1:反爬类型识别是 Phase 0 的 Phase 0
合并原 #28
不加任何 hook 先 navigate,观察 redirect_chain / initial_status / 加载的 JS 特征,三分法判定签名型/行为型/纯混淆。
用错档的工具不是效率差,是根本跑不通。
MCP 操作:
navigate(url) // 不传 pre_inject_hooks
→ 读 initial_status / final_status / redirect_chain
→ 按三分法判断表判定类型
规则 2:JSVMP 双路径决策
合并原 #11, #29, #30
识别到 JSVMP 后先判断走路径 A(算法追踪)还是路径 B(环境伪装)。
签名型反爬只有一条路:instrumentation(action='install', mode="ast") ,源码级插桩不动环境,是唯一能同时"观察 VMP"和"让挑战通过"的手段。
hook_jsvmp_interpreter(mode="transparent") 是 mode="proxy" 的签名安全备选,源码级插桩失败再退到这里。
规则 3:Cookie 归因优先于 setter hook
合并原 #1, #25
分析动态 Cookie 第一步永远是 analyze_cookie_sources(),它能区分三种模式:
- 纯 JS 写入
- 纯 HTTP Set-Cookie
- JS 算 token + 服务端带回来
RS/Akamai 最常见的第三种模式下,单纯 hook document.cookie setter 什么都抓不到。
规则 4:pre_inject_hooks 的正确定位
合并原 #26, #30
- 行为型反爬:可用,首屏挑战页(RS 412、Akamai 首包)必须用它在 navigate 时装好 hook
- 签名型反爬:不可用,永远不要对签名型反爬用它
规则 5:经验案例优先匹配 cacheOpts 区分变体
原 #40
同一 SDK 体系存在多个变体(单签名 vs 双签名、bdms.paths vs cacheOpts),Phase 0.5 指纹匹配时应优先检测 cacheOpts 和 X-Gnarly 来区分。
二、工具技巧(10 条)
规则 6:get_request_initiator 是黄金路径
原 #9
看到加密参数 → 获取请求 ID → get_request_initiator(request_id=N) → 直达签名函数,省去大量搜索。
规则 7:inject_hook_preset 一键到位
原 #10
不要手写常见 Hook,预设模板覆盖 xhr/fetch/crypto/websocket/debugger_bypass/cookie/runtime_probe。
规则 8:源码级插桩优先于运行时 hook(对 VM 自包含场景)
合并原 #23, #24
RS 5/6、Akamai sensor_data、webmssdk 这类"算法全部在 opcode dispatch 循环内"的 VMP,hook_jsvmp_interpreter 仍然看不到 switch/case 内部。
MCP 操作:
instrumentation(action='install', url_pattern="**/<VMP文件>", mode="ast", tag="vmp1")
<!-- v3.1.0: migrated from instrument_jsvmp_source -->
→ 是唯一能打开黑箱的工具
instrumentation(action='log', tag='vmp1', type_filter='tap_get', limit=200)
<!-- v3.1.0: migrated from get_instrumentation_log -->
→ hot_keys 指纹学习法 30 秒就能告诉你 VMP 读了哪些环境属性
规则 9:instrumentation(action='reload') 取代裸 reload
原 #27
装完 hook 想让它先于页面 JS 跑,裸 reload() 不能保证顺序。
MCP 操作:
instrumentation(action='reload')
<!-- v3.1.0: migrated from reload_with_hooks -->
→ 一步到位,默认 clear_log=True 拿到干净快照
规则 10:search_code(keyword, script_url=url) 定位大文件
原 #16
JSVMP 文件通常 200KB+,用 search_code(keyword, script_url=url) 在指定脚本中搜索,获取前后上下文。
规则 11:compare_env 是补环境的起点
原 #17
先在 Camoufox 中采集环境基准数据,再用 evaluate_js 分批采集细粒度值(compare_env 不覆盖 Function.toString / Symbol.toStringTag / DOM 布局),与 jsdom 逐项 diff。
规则 12:双签名场景必须同时 Hook XHR 和 fetch
原 #33
某些平台的 JSVMP 同时修改 XMLHttpRequest.prototype.open 和 window.fetch,只 Hook 一个通道会丢失另一半签名。
MCP 操作:
inject_hook_preset("xhr", persistent=True)
inject_hook_preset("fetch", persistent=True)
→ 两个通道都要 Hook
规则 13:MCP 侧 AST 让插桩在挑战页可用
原 #32
v0.5.0 把 AST 从页面内 Acorn 改为 MCP 侧 esprima,RS 412 挑战页也能跑。
instrumentation(action='install', ...) 的 last_mode_used 长期是 "regex (fallback)" 说明目标有太新语法。
规则 14:CSP 策略可能阻断 AST 模式插桩
原 #37
严格的 CSP 会阻止改写代码执行。v0.6.0 新增 csp_bypass=True 参数自动绕过。
规则 15:navigate 的 collect_response_chain 默认开启
原 #39
v0.6.0 起默认记录完整响应链,对签名型反爬的 412→200 判断更可靠。
三、Hook 与环境伪装踩坑(8 条)
规则 16:环境伪装优先于算法追踪
原 #18
如果 JSVMP 只是一个「签名黑箱」且可以在 jsdom 中加载执行,优先走路径 B(采集→对比→补丁),比追踪字节码执行快 10 倍。
规则 17:Function.prototype.toString 是 jsdom 环境伪装的第一杀手
原 #19
jsdom 所有 DOM 方法的 toString() 会暴露实际 JS 代码,必须用 WeakSet + 实例级覆写 + 源码模式正则三层防御。
规则 18:环境对比要分批采集
原 #20
单次 evaluate_js 代码太长会报错,分 4-5 批:
- navigator
- screen + window
- document + performance + toString
- DOM + Canvas + WebGL + Audio
规则 19:jsdom 环境补丁必须在 JSVMP 脚本加载前完成
原 #21
XHR Hook 的安装顺序决定能否截获最终 URL。
规则 20:服务端静默拒绝是环境检测失败的信号
原 #22
返回 HTTP 200 + 空 body(不报错),说明签名格式正确但环境指纹不匹配。
规则 21:Firefox 格式 native code 与 Chrome 不同
原 #35
Camoufox 基于 Firefox 内核,Function.prototype.toString 对原生函数返回含换行缩进格式。
Chrome: "function name() { [native code] }"
Firefox: "function name() {\n [native code]\n}"
jsdom 的 markNative 必须匹配采集基准浏览器的格式。
规则 22:cacheOpts 是新版 SDK 初始化的必传项
原 #34
旧版只需 bdms.paths,新版必须同时传入 cacheOpts。缺少 cacheOpts 会导致业务路径未注册,拦截器不触发。
规则 23:环境伪装前先确认签名函数入口
原 #38
在开始 6 步法的环境采集之前,先用 search_code 确认 JSVMP 的签名入口类型:
- 单通道 XHR
- 双通道 XHR + fetch
- 导出函数
- cacheOpts 初始化
四、协议优先反模式(7 条)
规则 24:先做最小补环境,不要上来就开浏览器
原 #5
协议优先的第一步。能用 Node.js crypto 解决的,不要用 vm 沙箱;能用 vm 沙箱的,不要用 jsdom;能用 jsdom 的,不要用浏览器。
规则 25:TLS 指纹是终极壁垒
合并原 #6, #36
算法全对但仍失败时,考虑 TLS 指纹:
- Node.js 用
got-scraping模拟 Firefox/Chrome TLS 指纹 - Python 用
curl_cffi
规则 26:签名不一致时逐环节对比
原 #13
排查链路(逐项对比脚本值 vs 浏览器值):
- 原始输入参数
- 参数排序/拼接字符串
- 时间戳(精度:秒 vs 毫秒)
- 随机串(长度、字符集)
- 密钥/盐值
- 中间摘要
- 最终密文(编码方式:hex/base64/自定义)
找到第一个偏差点。
规则 27:预热请求不是装饰
原 #2
/api2 类请求在运行时注入关键变量。跳过预热请求可能导致签名缺少必要的动态密钥。
规则 28:Node vm 沙箱 ≠ 浏览器
原 #3
有些调试干扰机制只在非浏览器环境触发。vm 沙箱中可能遇到:
window未定义document未定义navigator未定义- 定时器行为不同
规则 29:降级梯度必须逐级走
合并原 #43, #44
instrumentation(action='install', mode="ast")
→ 失败
instrumentation(action='install', mode="regex")
→ 覆盖率不足
hook_jsvmp_interpreter(mode="transparent")
→ 日志太少
hook_jsvmp_interpreter(mode="proxy") ← 仅行为型可用
→ 破坏签名
路径 B(jsdom 环境伪装)
→ 也失败
向用户说明情况
每级至少尝试一次并记录失败原因。想放弃时先回查 cases/ 和 common-pitfalls.md。
规则 30:case 文件的价值随实战次数指数级增长
v3.2.0 改写(原"Session 档案与经验库互补")
第一次分析某站点时写的 case 可能粗糙;第二次分析(升级或变体)时用 case 发现 80% 还成立、20% 变了,就把变化追加到 case 的"变体章节"。三五次之后,这个 case 会覆盖该站点的主要变体谱系,复用价值极高。
case 文件的"可验证事实清单"段列出 5-15 条最小可验证事实(如"X-Bogus 长度 28""webdriver === false"),下次同站升级时逐条手动核对找出"哪些变了"就是今天的工作范围。
已合并/迁移的旧经验法则索引
| 原编号 | 原标题 | 去向 |
|---|---|---|
| #1 | Cookie setter 最高性价比 | → 合并到新 #3(Cookie 归因优先) |
| #4 | WASM panic 常常是环境缺失 | → 移到 references/troubleshooting.md |
| #7 | 真假请求链是常见干扰 | → 移到 references/troubleshooting.md |
| #8 | HTTP/2 可能是唯一的"密码" | → 移到 references/troubleshooting.md |
| #11 | JSVMP 路径选择 | → 合并到新 #2 |
| #12 | JSVMP 中 String.fromCharCode 是高频信号 | → 移到 references/jsvmp-analysis.md |
| #14 | Python execjs 复用 context | → 移到 references/workflow-overview.md |
| #15 | Hook 必须持久化 + 防覆盖 | → 已在工具说明中覆盖 |
| #23 | 源码级插桩优先 | → 合并到新 #8 |
| #24 | hot_keys 指纹学习法 | → 合并到新 #8 |
| #25 | Cookie 归因 | → 合并到新 #3 |
| #26 | pre_inject_hooks 定位 | → 合并到新 #4 |
| #28 | 反爬类型识别 | → 合并到新 #1 |
| #29 | 签名型只走源码插桩 | → 合并到新 #2 |
| #30 | transparent 备选 | → 合并到新 #2, #4 |
| #41 | 开 session 多 10 秒省几小时 | → 已合并到硬约束 Checklist CHECK-4 |
| #42 | 进新域第一反应 list_sessions | → 已合并到 Checklist CHECK-3 |
| #43 | 降级梯度逐级走 | → 合并到新 #29 |
| #44 | 过期不等于失效 | → 合并到新 #29 |
| #45 | 断言价值指数递增 | → 合并到新 #30 |
| #46 | Session 与经验库互补 | → 合并到新 #30 |
SKILL.md 核心层保留了前 10 条最常用的经验法则(规则 1-10 的精简版) 完整 30 条在本文档 反模式清单:references/common-pitfalls.md