尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

爬虫逆向心法:从抓包分析到JS逆向与反爬破解的实战细节

爬虫逆向心法:从抓包分析到JS逆向与反爬破解的实战细节 一个老爬虫的逆向心法那些网上不说的细节我一次性抖出来写爬虫最怕什么不是被封IP不是被识别而是——你看得见数据在那里却怎么也拿不出来。这种卡壳的感觉凡是做数据采集的朋友都懂。今天想以学习心得的形式把我这几年在爬虫逆向路上攒下的零零碎碎、小技巧小知识整理出来尽量按实际踩坑的顺序讲题目带“持续更新”四个字是因为代码会变、网站会变经验也必须跟着更新。不论你是刚入门Python爬虫的萌新还是已经跟反爬机制缠斗许久的老手这篇文章里总有几个细节能帮你省下几小时的折腾时间。我会尽量用大白话把原理说清楚再把实操步骤写明白代码能贴就贴思路能拆就拆。从抓包开始的逆向基本功做任何爬虫逆向项目之前我习惯先花十分钟把通讯链路理清楚。这里的核心就一句话搞清楚数据是从哪里来的再决定该怎么拿。1.1 响应内容定位看清你是哪一类爬虫拿到一个目标站点我第一件事永远是开浏览器开发者工具切到Network面板刷新页面看请求列表。这里很多人容易犯一个错一上来就去找XHR或Fetch请求结果遇到纯HTML渲染的页面就懵了。实际上爬虫逆向第一步不是“找接口”而是判断数据属于静态渲染、JSON接口、还是加密传输。静态渲染数据全部嵌在HTML里直接用XPath或正则提取即可比如常见的列表类网站。JSON接口请求返回的是结构化数据直接用requests.json()处理省事。加密传输响应里是乱码或base64密文或者在JavaScript里能看到JSON.stringify后的一堆转义字符这时候才需要进入真正的逆向环节。判断方法很简单在Network面板里搜索某个页面上可见的关键词。如果搜索结果出现在HTML文档里就是静态渲染如果出现在某个接口的响应里则是JSON接口如果哪儿都搜不到那就是加密了。1.2 XPath中的text函数细节很多朋友问过我用XPath提取文本时为什么老取不到值。这里有个非常容易踩的坑text()只能取当前节点的直接文本节点如果目标文本被子标签包裹比如span2024年/span12月25日你用.//p/text()就只会得到“12月25日”前面那半截没了。我常用的解决方案是优先用.//p[contains(text(),目标词)]做条件定位再用string(.)取全文或直接normalize-space(.//p)拿到子标签加文本的拼接结果如果页面用懒加载渲染数据text()找不到内容多半是渲染未完成配合等待策略使用。这个细节看着不起眼实际排查中经常能让人卡上半小时。JS逆向的破局思路如果说普通爬虫是“伸手拿数据”那逆向就是“先撬锁再拿数据”。整个JS逆向的核心其实就俩字跟栈。2.1 断点不是瞎打先找请求发起者接手一个加密接口时不要急着在Call Stack里乱翻。先回到Network面板找到目标请求右键选择“Copy as cURL”从里面看看有没有sign、token、timestamp这类自定义请求头。有的话就在JavaScript代码里搜这个参数名无脑搜往往最有效。搜出来之后直接下断点然后重新触发一次请求。这时候栈会断在你搜索的那一行接下来用“Step into next function call”F11慢慢往下走观察参数是怎么从明文变成加密串的。这里我总结过一个规律真正生成签名的函数通常都不是你搜到的那个参数名本身而是它被调用时的来源。所以看到参数赋值处别急着看它怎么算先回头看这个值是哪个函数返回的然后进去看。2.2 Hook是逆向的万能钥匙网上很多教程教人“补环境”确实在高强度反爬下这是绕不开的但日常工作中更立竿见影的手段是Hook。原理不复杂在目标JS执行前把它要调用的关键函数窗口期拦截下来打印出入参和返回值。举个例子如果一个加密参数最终会调用window.encrypt你可以直接在Console里执行var originalEncrypt window.encrypt; window.encrypt function() { console.log(参数:, arguments); var result originalEncrypt.apply(this, arguments); console.log(结果:, result); return result; };这样当你再触发请求时控制器会把每次加密的入参和结果全部打印出来。定位加密位置从“大海捞针”变成了“守株待兔”。2.3 补环境时最容易漏掉的三件事真到了需要补环境跑通整个加密流程的地步我建议你把下面三样当作清单逐项检查toString方法很多站点会对函数做检测通过Function.prototype.toString判断你是不是原生函数。补环境时记得把关键函数转成原生模板否则一调就露出马脚。DOM操作加密逻辑里不一定只有算法还可能混进document.addEventListener、localStorage等内容。这些浏览器环境API在Node里默认不存在需要手动构造。正则特征部分网站的加密JS里藏了对Chrome UA的正则校验一旦用Node默认UA就会被判定为异常。我在做某大厂签到逆向时就栽在过这个细节上后来统一Header后秒过。App逆向的入门路径网站爬腻了很多人会转向App逆向。跟JS逆向相比App逆向的战线更长思路也不同但入门路径非常清晰。3.1 抓包配置决定成败做App逆向第一步永远是抓包。iOS和安卓的抓包方式略有差异但核心都是让App的流量经过你的代理。安卓7.0以下用户证书就能解密HTTPS安卓7.0及以上App默认不信任用户CA证书所以需要把证书挪到系统证书目录或者是用Frida绕过SSL Pinning。iOS除了证书信任设置还要注意部分App做了双向校验。提起Frida它比抓包工具“高一档”的地方在于能直接对App进程进行动态插桩。想调用App内部的某个加密函数不用逆向算法直接通过RPC把它捞出来用这是目前最优雅的解法。大致流程是先安装frida-server到手机上注意版本要和电脑端frida一致然后跑一段JavaScript脚本来hook目标函数。3.2 安卓逆向中的脱壳问题现在App越来越流行加固dex文件被加密后静态分析工具看着就像天书。这时候得先脱壳。常用的工具有frida-dump、objection、r0capture核心思路都是让App在内存里“现出原形”再把内存中的dex拉出来。成功脱壳后再用Jadx反编译代码可读性会高很多。这里有一个我踩过很多次的坑脱壳的时机很重要必须在App加载完但函数还没被释放的窗口期去dump。我一般会在App启动后等两三秒再执行脱壳命令成功率会高出很多。工程化真正的高效藏在架构里逆向搞定了数据能拿到了很多人以为就完了。其实项目能不能长期稳定跑下去拼的是工程化能力。4.1 爬虫可视化界的利器爬虫到了中后期就需要一个可视化界面来监控任务运行状态了。Python爬虫可视化界面的方案我比较推荐Streamlit或Gradio轻量级几百行代码就能把任务列表、抓取进度、失败重试统计全部展示出来。针对需要手动干预的采集任务甚至可以做一个简单表单输入编号即可启动指定爬虫。为什么推荐可视化因为当爬虫数量多了以后你根本记不住哪个任务挂在哪台机器上。一个简单的Dashboard比任何日志系统都直观。4.2 多线程与信号量的配合Python爬虫用多线程加速是最常见的做法但很多人直接把线程池线程数拉到50不加控制。结果就是对方服务器直接把你整个IP段封掉。我的习惯是线程池负责“并发能力”信号量负责“并发上限”。import threading import requests # 信号量控制同时进行的请求数 semaphore threading.Semaphore(5) def fetch(url): with semaphore: response requests.get(url, headersheaders) return response.text这样不管线程池开多大真实并发始终被信号量锁在一个安全值内。目标网站压力小爬虫稳定性反而更高。防爬防护的思路既然做爬虫就得站在反爬的立场上想想自己是怎么被防的。这里我写几个服务端常用的反爬策略作为逆向练习的“解题思路”备查。5.1 Controller层防爬设置在一线网站开发里Java的Controller层经常被用来做防爬拦截主要手段包括请求来源校验检查Header里的Referer、Origin频率限制结合Redis做计数器同一IP或同一用户标识在窗口期内超过阈值就拒绝服务动态令牌前端在请求前向后端获取一个token每次请求带着后端验签。这就构成了一个典型的“动态加密请求头”场景。理解了这些服务端防护手段逆向的时候就能顺着思路找对应解法频率限制用代理池动态令牌用Hook定位生成逻辑。5.2 响应加密与前端解密还有个常见的防爬设计是服务端返回密文由前端解密后渲染。这种逆向时搜索的关键词不是“sign”而是“decrypt”“decode”或“JSON.parse”。前端解密代码里通常会调用某个标准库如CryptoJS识别出算法种类AES、RSA、DES后就能直接在Python里复现。比如AES加密参数无外乎key、iv、mode、padding四件套在PyCryptodome里一一对应即可。不要被一个看起来几百行的混淆代码吓到扒掉外衣后里面就这几样东西。逆向中的验证码与字体反爬验证码和字体反爬是所有爬虫工程师绕不开的两座大山。6.1 打码平台的正确打开方式遇到验证码不必每次都走机器学习路线。短期项目用打码平台成本低效率高。我自己用得比较顺手的方案是先用ddddocr本地识别纯数字/英文验证码准确率大概能到90%以上如果识别率不达标再切换第三方打码平台一次调用几分钱整体效率高很多。注意打码平台的识别结果经常是字符串需要确认是否含空格和大小写提前做好字符清洗。6.2 字体反爬的破解逻辑字体反爬的原理是把真正显示的文字藏在一个自定义字体文件里页面里塞给你的只是一堆编码。破解起来思路清晰F12找到 font-face 定义下载woff/ttf文件用fontTools解析把glyph名字和页面上的字符编码对应起来再用fontTools的getBestCmap()建立映射字典完成密码本替换。这个方法对绝大多数字体反爬都有效难点只在第一次解析后要存好映射关系定期重跑。如何在逆向中高效利用AI最近AI辅助逆向的趋势越来越明显。我自己试下来最受用的是代码解释和脱混淆。7.1 用AI看懂混淆代码遇到一段看得头晕的混淆代码直接把整段丢给大模型让它解释这段代码在做什么。AI对常见的混淆模板比如控制流平坦化、字符串加密识别率很高即使不能直接还原也能帮你快速定位主逻辑。特别是遇到AST抽象语法树级别的混淆AI给的还原思路比自己硬啃效率高一个量级。7.2 自动逆向的边界在哪现在有些工具号称能自动逆向“一键还原算法”但从实际体验看还处于初级阶段。它们擅长的是把“简单的混淆”还原成可读代码一旦牵扯到复杂的执行流程重建、多步骤参数依赖工具的可靠性就大幅下降。所以我对自动逆向的态度是能用它做粗糙分析但核心结论必须自己跟栈验证一遍。爬虫的长期稳定运行技巧最后聊一个容易被忽略的话题跑得久。8.1 代理池与cookie池的运维爬虫挂多了代理池和cookie池就成了基础设施。代理池的核心是“自动验证-自动剔除失效IP”cookie池的核心是“自动登录-自动续期”。这两块做好能省下一大堆人工维护的时间。推荐一个轻量级的做法把代理和cookie都存Redis用Scheduler定时验证通过PUT/GET接口提供给爬虫调用。没必要引入很重的框架简单够用就好。8.2 User-Agent指纹轮换UAUser-Agent轮换是基础中的基础但很多人只换UA不换其他Header导致指纹特征明显。我建议至少把以下几项一起随机化User-AgentAccept-LanguageAccept-EncodingSec-Ch-UaChromium系Sec-Fetch-*如果目标站点还能识别浏览器指纹最终解法是直接用Playwright或Puppeteer启动真实浏览器来操作代价是性能和资源占用高但换来的是最自然的浏览器指纹。结尾建议这篇文章写到这里已经覆盖了从入门抓包到工程化部署、再到服务端反爬视角的完整链路。受限于篇幅“持续更新”的系列还会继续写比如JS逆向的AST还原、Android脱壳的进阶实操、分布式爬虫的调度设计都会单独拆开来讲。最后分享一个个人经验逆向学习没有捷径最好的方式就是找一个感兴趣的目标站点从简单接口开始一步步走完“抓包—定位—分析—还原—工程化”的完整流程。别看网上一堆“一键破解”的教程真正属于自己的能力都是在一次次跟栈和踩坑中长出来的。如果你在实操中遇到具体的卡壳点欢迎在评论区把报错或现象写出来我看到会回复。毕竟这行最靠谱的老师就是彼此踩过的坑。
返回列表