☰
Akamai3.0反爬深度解析:传感器数据还原与无头浏览器实战
2026/10/14 5:19:36 网站建设 项目流程

简介:这份源码包面向已具备一定爬虫基础、希望深入理解Akamai反爬机制的开发者,聚焦Akamai 3.0版本的逆向分析思路与应对策略。内容围绕9个视频教程展开,涵盖2.0与3.0的版本区分、cookie有效性分析,以及sensor_data主流程、ajr、mdn、ffs、inf、din、mst、dvc等关键参数的逆向拆解,并针对状态码428给出动态分析改版方法,帮助读者建立从旧版到新版的完整认知框架。资源包共3个文件,以inscode工程配置、html页面与gitignore为主,压缩后约6KB,结构轻量,便于快速导入查看与二次整理。目前已有764人学习下载,适合需要对照视频梳理参数逻辑、排查请求异常并沉淀逆向笔记的中高级爬虫开发者参考。

1. akamai3.0反爬到底在防什么:从一次请求被拒说起

如果你最近在抓某个海外电商或航司的票价接口,大概率遇到过这种情况:请求发出去,返回的不是数据,而是一段混淆得亲妈都认不出的 JS,或者干脆一个 403,连响应头都透着“我不欢迎你”的意思。这背后很可能就是 akamai3.0 在起作用。它跟早期版本最大的区别,是把校验逻辑从“看你带没带某个 cookie”升级成了“看你的浏览器环境、行为轨迹、传感器数据是否像一个真人”。换句话说,它不再只查身份证,而是开始观察你走路姿势自不自然。

这个标题里的“反爬教程[源码]”,核心诉求其实就三件事:搞明白 akamai3.0 的校验入口在哪、怎么把关键参数还原出来、以及怎么在代码里稳定复现。适合谁看?适合已经能熟练使用 requests 或 httpx 发请求,但卡在动态 cookie 生成这一步的爬虫工程师;也适合做数据采集方案选型的技术负责人,需要判断这个方向投入产出比到底划不划算。接下来我会按“先看懂它查什么 → 再动手还原 → 最后避开那些让我通宵的坑”这条线,把整个流程拆开讲。

2. akamai3.0 的校验链路拆解:从 _abck 到传感器数据

2.1 三个核心 cookie 的分工与生命周期

Akamai 3.0 的校验结果最终会体现在三个 cookie 上:_abck、bm_sz、ak_bmsc。很多人一上来就盯着_abck看,觉得只要把它搞对就万事大吉,结果发现请求还是被拒。血泪经验是:这三个 cookie 是联动的,缺一个或者顺序不对,整个链路就断了。

ak_bmsc通常是第一道门槛,由边缘节点直接下发,有效期很短,主要用来做第一层速率和 IP 信誉判断。bm_sz更像一个会话标识,配合传感器数据一起提交。而_abck是最终的成绩单,它的值里编码了校验结果、时间戳和一堆加密后的状态位。你真正要攻克的,是让_abck从“未通过”状态变成“通过”状态,而这个转变发生在你提交传感器数据之后。

常见做法是先用一个干净的会话去请求目标页面,拿到初始的ak_bmsc和一段混淆 JS,然后在无头浏览器里执行这段 JS,采集它生成的传感器数据,再带着这些数据去请求一个特定的校验接口,最后拿到更新后的_abck。整个过程环环相扣,任何一步的环境不对,_abck都不会变绿。

2.2 传感器数据到底采集了什么

传感器数据(sensor_data)是 akamai3.0 最核心的输入。它不是一个简单的字符串,而是一段经过多层编码的、包含了几十个字段的 JSON 结构。我把它拆开看过,里面大致包含这几类信息:

第一类是环境指纹,比如屏幕分辨率、时区、语言、User-Agent、Canvas 指纹、WebGL 渲染器信息。这些字段如果和你的请求头对不上,直接露馅。第二类是行为轨迹,包括鼠标移动的坐标序列、点击事件的时间戳、键盘按键的间隔。注意,它不只看你有没有动,还看你的移动曲线是否符合人类肌肉运动的规律——匀速直线运动反而会被标记。第三类是时间相关数据,比如页面加载到各个事件触发的时间差,这个差值的分布也有统计模型在卡。

这些数据会被 JS 里的一个混淆函数序列化,然后经过类似 AES 或自定义的异或加密,最后拼成一个长字符串。你在 Network 面板里看到的那个sensor_data参数,就是最终产物。想靠纯 Python 硬算出来几乎不可能,因为加密密钥是动态生成的,跟当前页面的 JS 执行环境绑定。

2.3 校验接口的触发时机与返回特征

校验接口通常长这样:/akam/13/xxxxx或者一个看起来像静态资源路径的 URL。它不会在你页面加载完就立刻触发,而是会等一段时间,或者等你触发了某个事件(比如滚动、点击)之后才发出去。这个设计就是为了收集足够的行为数据。

返回内容一般是一个 JSON,里面有个status字段。如果status是 200 或者类似成功码,同时响应头里的Set-Cookie更新了_abck,那就说明这一轮过了。如果返回 403 或者_abck没变,说明传感器数据被判定为机器生成。这里有个细节:有时候接口返回 200,但_abck的值只是刷新了时间戳,状态位没变,这表示“暂时放过你,但没完全信任”,后续请求频率一高还是会封。

3. 用无头浏览器还原传感器数据:环境搭建与注入时机

3.1 选型:为什么我最终放弃了纯协议方案

一开始我也试过纯协议方案,用 Python 去模拟 JS 的加密逻辑。花了三天把混淆代码里的字符串数组还原出来,又跟了一遍加密函数,结果发现密钥里混入了performance.now()的精度值和Date.now()的偏移量,这两个值在 Node.js 里和真实浏览器里对不上。更坑的是,Akamai 会检测navigator.webdriver、window.chrome这些属性,纯协议方案在这些点上全是破绽。

后来转向无头浏览器方案,用 Playwright 或者 Puppeteer 驱动一个真实的 Chromium。好处是环境天然真实,JS 执行结果和真人浏览器几乎一致。代价是资源消耗大,每个会话都要启动一个浏览器上下文,并发上不去。折中方案是用浏览器池,复用上下文,但每次请求前要清理 cookie 和 storage,否则会话会串。

3.2 注入脚本的时机:在 JS 加载前还是加载后

注入时机的选择直接决定你能不能拿到完整的传感器数据。如果你在页面 JS 加载完之后才注入,Akamai 的采集脚本可能已经执行完了,你拿到的数据是残缺的。正确做法是在Page.addInitScript阶段就把钩子挂上去,拦截关键函数。

具体要 hook 哪些函数?我一般会盯这几个:XMLHttpRequest.prototype.send、fetch、navigator.sendBeacon,以及Object.defineProperty对document.cookie的 setter。这样当 Akamai 的脚本尝试发送传感器数据时,我能第一时间截获到明文(或者至少是加密前的结构)。下面是一段 Playwright 的注入代码示例:

# 在页面任何脚本执行前注入钩子 async def inject_hooks(page): await page.add_init_script(""" (function() { // 保存原始 send 方法 const originalSend = XMLHttpRequest.prototype.send; window.__captured_sensor = null; XMLHttpRequest.prototype.send = function(body) { // 只拦截包含 sensor_data 的请求 if (body && typeof body === 'string' && body.includes('sensor_data')) { window.__captured_sensor = body; console.log('[HOOK] sensor_data captured, length:', body.length); } return originalSend.apply(this, arguments); }; // 同时 hook fetch,防止对方改用 fetch 发送 const originalFetch = window.fetch; window.fetch = function(url, options) { if (options && options.body && typeof options.body === 'string' && options.body.includes('sensor_data')) { window.__captured_sensor = options.body; } return originalFetch.apply(this, arguments); }; })(); """)

这段代码的逻辑是在页面初始化阶段就替换掉XMLHttpRequest.prototype.send和window.fetch,当请求体里出现sensor_data关键字时,把整个 body 存到window.__captured_sensor里。参数说明:add_init_script保证在页面任何脚本之前执行;body.includes('sensor_data')是过滤条件,避免抓到无关请求;originalSend.apply保证原始功能不受影响。拿到这个 body 之后,你就可以把它存下来,后续用同样的环境去重放。

3.3 采集后的数据清洗与重放

截获到的sensor_data不能直接拿去用,因为它里面绑定了当前页面的_abck初始值和一些一次性 token。如果你换个会话重放,校验接口会直接拒绝。我一般会做两步清洗:先把sensor_data解码(通常是 base64 加一层异或),看看里面的时间戳和页面 ID 字段,然后把当前会话的 cookie 和这个数据绑定在一起,在同一会话内完成提交。

重放的时候要注意请求头的顺序和大小写。Akamai 的校验接口对Content-Type、Origin、Referer这些头很敏感,少一个或者值不对,都会导致校验失败。我习惯用page.request.post来发这个请求,因为它会自动带上浏览器上下文里的 cookie 和默认头,比手动构造更省心。

4. 避坑与排查:那些让我通宵的翻车现场

4.1 坑一:无头模式被识别,_abck永远不变绿

现象:用 headless 模式跑,传感器数据也提交了,但_abck始终是初始值,校验接口返回 403。原因:Chromium 的 headless 模式有一些特征,比如navigator.webdriver为 true、window.chrome缺失、plugins数组为空。Akamai 的 JS 会检测这些。解决:用playwright的chromium.launch(headless=False)配合虚拟显示,或者用playwright-stealth之类的补丁库把特征抹掉。我一般会手动覆盖几个关键属性:

// 在 add_init_script 里加上这些 Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); window.chrome = { runtime: {} }; Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] });

4.2 坑二:传感器数据长度对不上,被判定为截断

现象:截获的sensor_data长度只有正常值的一半,提交后校验失败。原因:Akamai 的采集脚本是分片发送的,或者在某些事件触发后才补全数据。你 hook 到的可能只是第一段。解决:不要只抓第一个包含sensor_data的请求,要监听所有相关请求,把 body 拼接起来。或者更稳妥的做法是等页面完全稳定(比如networkidle)之后再从window.__captured_sensor里取最终值。

4.3 坑三:IP 信誉被标记,换浏览器也没用

现象:本地调试一切正常,部署到服务器上就全挂。原因:Akamai 会结合 IP 的历史行为做信誉评分。如果你的服务器 IP 之前被大量爬虫用过,或者短时间内请求频率过高,它会直接给你一个低信誉分,这时候传感器数据再真也没用。解决:控制请求频率,给每个会话分配独立的出口 IP,并且定期轮换。别用那些被用烂的机房 IP 段。

4.4 坑四:cookie 作用域搞错,_abck写不进去

现象:手动把_abck塞进 cookie jar,但请求时发现没带上。原因:_abck的 domain 和 path 属性有特定要求,如果你用requests的cookies.set方法,默认 domain 可能不对。解决:用requests.cookies.create_cookie显式指定 domain 和 path,或者直接用浏览器上下文来管理 cookie,别手动干预。

4.5 坑五:JS 执行顺序错乱,hook 被覆盖

现象:注入的 hook 代码明明写了,但window.__captured_sensor一直是 null。原因:Akamai 的脚本可能在你注入之后又重新定义了XMLHttpRequest.prototype.send,把你的 hook 覆盖掉了。解决:用Object.defineProperty把send属性设为不可写,或者在 hook 里加一个定时器,每隔几毫秒检查一次send是否还是你的版本,不是就重新替换。

5. 进阶:把单次成功变成稳定管道的三个技巧

5.1 会话池与指纹隔离

单次跑通不难,难的是持续稳定地跑。我的做法是维护一个浏览器上下文池,每个上下文对应一个独立的指纹(User-Agent、屏幕分辨率、时区、Canvas 噪声)。每次任务从池里取一个空闲上下文,用完就销毁重建,避免指纹被关联。池的大小根据目标站点的容忍度调整,一般控制在 5 到 10 个并发,再高就容易触发风控。

5.2 传感器数据的缓存与复用边界

有些站点的传感器数据在短时间内可以复用,比如同一个会话内连续请求多个页面,不需要每次都重新采集。但要注意,_abck的有效期通常只有几分钟到十几分钟,过期后必须重新走一遍校验流程。我一般会记录每个会话的_abck下发时间,在过期前 30 秒主动刷新,避免请求到一半突然失效。

5.3 监控与降级:怎么判断今天还能不能跑

上线之后不能当甩手掌柜。我会在采集管道里加两个监控指标:一是校验接口的成功率,如果连续 10 次失败,就自动降低并发或者暂停任务;二是_abck的更新频率,如果发现它长时间不更新,说明当前 IP 或指纹已经被拉黑,需要切换资源。降级策略也很简单:主方案走无头浏览器,备用方案走纯协议加手动打码,虽然成功率低,但至少能保住一部分数据。

这套东西我断断续续调了快两个月,最大的教训就是别跟 Akamai 的 JS 硬刚加密算法,那是无底洞。把精力花在环境模拟和行为轨迹的拟真上,回报率高得多。另外,每次它更新版本,先别急着改代码,用浏览器手动走一遍流程,看看 Network 面板里多了哪些请求、少了哪些字段,往往比埋头读混淆代码快得多。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询