资讯详情

资讯详情

抓包实战完全指南:从浏览器到Charles,破解爬虫反爬难题

做爬虫最让人头疼的事多半不是代理池不够大而是看着浏览器里明明正常返回的数据到了Python里却怎么也调不对。要么带全了参数访问接口还是被拒要么发现页面数据全藏在异步请求里要么翻遍响应HTML也找不到关键值。这时候抓包技术就是那根救命稻草。所谓抓包就是拦截客户端与服务端之间的网络流量把黑盒通信变成肉眼可见的HTTP请求和响应让你看清每一次页面操作背后到底发了什么、回了什么。这篇文章我会从浏览器开发者工具讲到Charles这类代理工具再到Wireshark和签名分析完整拆解爬虫开发中最常用的抓包实战技能适合刚接触爬虫但被反爬搞到怀疑人生的新手也适合想系统补全网络调试能力的进阶玩家。1. 抓包到底在抓什么一个HTTP请求的完整旅程1.1 请求与响应的骨架爬虫真正需要关心的部分抓包的本质是流量观察而爬虫需要观察的无非两类信息客户端发出的请求长什么样服务端返回的数据长什么样。典型的HTTP请求分为四段请求行、请求头、请求体仅POST等方法有、可选的分隔和尾部。请求行包含方法、URL和协议版本例如GET /api/list?page1 HTTP/1.1。请求头则是一堆键值对里面藏着User-Agent、Cookie、Referer、Accept、Content-Type等大量信息。响应也有四段状态码、响应头、响应体。很多爬虫跑不通的根因不在Python代码而在这些字段的差异。举个例子某站点搜索接口要求请求头必须带X-Requested-With: XMLHttpRequest代表这是一次AJAX请求服务端才返回结构化数据你用requests直接get不带这个头服务端当成普通浏览器访问直接抛给你一个整页HTML或验证码页面。类似这种细节如果你打开浏览器开发者工具看一眼十秒钟就能发现不看可能排查一下午。再比如Content-Type这个字段它决定服务端怎么解读请求体。常见的application/json要求你发送JSON字符串application/x-www-form-urlencoded要求你发送keyvaluekey2value2格式。抓包页面里这些字段都明文写着改成匹配的格式成功率立刻大幅提升。1.2 为什么HTTPS时代抓包都要“装证书”中间人的原理现在几乎没有纯HTTP的网站了打开抓包工具一看全是TLS加密的乱码。所谓HTTPS抓包实际上是在客户端与服务端之间插入一个代理角色也就是常说的中间人攻击测试思路。代理与真实服务端建立一条TLS连接获得明文数据再把它封装成客户端可验证的响应。为了让客户端信任它代理会生成一张自己的根证书并要求你把这张根证书安装进系统的信任列表。这样客户端看到由该根证书签发的服务器证书时会认为连接是安全的于是代理就能解密流量。很多新手卡在这一步手机连上代理后访问任何HTTPS网站都提示“证书不受信任”或者App直接把请求拒绝掉。其实原因很简单——根证书没有正确安装或者安装在了错误的位置。记住一句话抓包工具能不能看到明文完全取决于客户端是否信任你导入的根证书。信任了代理就是透明的不信任代理只能看到一条CONNECT隧道命令。1.3 工具选型三类抓包工具怎么选先给结论工具不在于多而在于你知道什么时候用哪个。我个人的习惯是分成三档。工具类型代表核心能力主要局限适用场景浏览器开发者工具DevTools零配置查看HTTP、WebSocket请求只能抓浏览器自身流量Web页面调试本地代理工具Charles、Fiddler配置代理后抓手机/桌面应用流量需要手动装证书移动App分析协议分析工具Wireshark抓取网卡原始流量看底层协议学习成本高、内容噪声大TCP、TLS、DNS排查浏览器开发者工具是日常使用频率最高的按F12打开切到Network标签刷新页面所有请求一目了然。不需要额外配置没有代理和证书的坑适合第一时间定位接口。Charles和Fiddler的核心价值在于移动端抓包。它们本质是一个HTTP代理服务器电脑上启动后监听一个端口手机或模拟器把网络代理指向电脑IP和该端口流量就会经过Charles。此时再安装信任Charles根证书就能看到App发出的HTTPS明文内容。Wireshark则属于终极武器它直接抓网卡数据包能看到TCP三次握手、TLS ClientHello、DNS查询等底层细节。它的使用场景很聚焦当你怀疑请求根本没发出去、被防火墙拦截、或者走的是非HTTP协议时才轮得到Wireshark登场。日常写爬虫大多数时候用前两档就足够了。2. 零基础也能上手的浏览器开发者工具抓包2.1 打开Network面板看懂瀑布图以Chrome为例打开需要分析的目标页面按F12切到Network。这个面板顶部会显示所有请求的列表每一行就是一个HTTP请求。关键信息包括Name、Status、Type、Initiator、Size、Time和Waterfall。新手最容易忽略的是Initiator列它告诉你这个请求是由哪个脚本发起的。比如某页面的数据是滚动到页面底部才加载出来的Initiator会显示一个onload或某个JS文件点进去还能跳到对应的调用栈。看到瀑布图后先别急着逐个点开。我的经验是先整体扫一眼这些请求的Type列把XHR和Fetch两种类型圈出来因为绝大多数动态数据都来自这两个类型的异步请求。HTML文档、图片、CSS、JS文件几乎不可能是爬虫需要的数据源可以直接过滤掉。2.2 快速筛选关键请求的实用技巧请求一多眼花缭乱。这里有三个非常实用的操作第一按类型过滤。点面板顶部的Fetch/XHR按钮立刻把非数据类请求隐掉。第二按关键字搜索。在Network面板的过滤框里输入接口路径中的特征词比如list、search、data或者输入响应体里某个已知字段名。第三重新触发操作。如果页面是点击按钮后动态加载数据需要在输入框里搜索某个关键词然后点击搜索按钮这个时候Network面板会自动多出几条请求新出现的那条往往就是目标接口。还有个很多人不知道的小技巧右键点击某个请求选择“Save all as HAR with content”可以把所有请求导出成HAR文件然后丢到Charles或在线工具里查看。如果你需要在爬虫中复现多个关联请求的完整顺序用HAR文件做参考会直观得多。2.3 “Copy as cURL”把浏览器请求直接变成Python代码我见过太多人一个个字段抄请求头费时费力还会抄错。正确的姿势是右键点击Network面板里的请求选择Copy - Copy as cURL。此时剪贴板里会得到一条完整的curl命令包含请求方法、URL、请求头、Cookie和POST数据。拿到这条curl命令后有两种方式转成Python。最省事的是找在线curl转Python工具粘贴后直接生成requests代码。如果你想更可控就自己拆解curl命令里-H后面的每个参数就是请求头字典的一项-d或--data-raw后面的就是requests的data或json参数--compressed表示需要解压gzip。这里有一个经验复制cURL时最好先清空页面Cookie或者使用无痕窗口操作这样拿到的是干净的未带Cookie的请求避免后续爬虫中被动态Cookie迷惑。还有一点要注意复制出来的cURL可能包含--header sec-ch-ua: ...这种大量前端指纹信息。首次测试可以全带后面正式写代码时逐步删减找出服务端真正必检的字段否则你的请求头会被一堆冗杂的浏览器特性绑死。3. 进阶用代理工具抓移动端App的HTTPS包3.1 配置代理手机和电脑连进同一局域网假设你已经在电脑上启动了Charles默认会监听8888端口。要让手机流量经过Charles需要做两件事让手机和电脑连同一个WiFi然后在手机WiFi设置里把代理改成手动服务器地址填电脑的局域网IP端口填8888。这里的坑在于防火墙。Windows或macOS的防火墙会拦截非本机发起的连接第一次用的时候如果发现手机打开网页走不了八成是防火墙没放行Charles。解决方法是在系统防火墙里允许Charles或对应端口通过。配置完成后打开手机任意网页Charles里会瞬间弹出一大堆请求说明流量已经被拦截到了。如果没有检查手机代理IP是否写错、有没有连到同一个路由器、以及是不是开了流量上网。3.2 安装根证书iOS与Android的平台差异手机能连上代理只算成功一半接下来的HTTPS明文还得靠证书。在iOS上用Safari访问chls.pro/ssl下载并安装描述文件再到“设置-通用-关于本机-证书信任设置”里把Charles证书完全信任。Android上如果你是Android 6或更低系统下载证书后安装到“用户证书”即可Android 7及以上App默认不再信任用户安装的CA证书这会导致很多App抓包时提示SSL错误或直接崩溃。对于Android高版本常见做法是把证书安装到系统证书目录这需要Root权限或者使用一些调试框架绕过。但这里我想强调一下边界绕过证书校验的手段应该只用于你自己开发调试的设备或已获得测试授权的应用不要用在不怀好意的场景里。换个思路如果目标App是你自己的应用直接在代码里暂时关闭证书校验就能省掉系统证书的坑。3.3 在Charles中定位纯异步接口与加密参数移动端App的数据加载节奏和网页不同很多页面打开时一次性并发发出数十个请求有的是统计上报有的是配置拉取有的是真正的业务接口。用Charles的放大镜搜索功能输入页面上看到的关键文字能快速定位到包含该数据的响应来源。定位到接口后双击请求看到请求头和请求体的全部参数这是后续写爬虫的依据。举个最常见的加密参数场景某App的列表接口地址是https://api.example.com/v1/list?page1ts1688888888signab3f...。其中page是页码ts是当前秒级时间戳sign是一串32位小写十六进制。此时可以推测sign大概率是MD5。把抓到的参数去掉sign后按key排序拼接加上某个密钥再拼上时间戳做一个MD5和抓到的sign比对。如果一致说明签名规则猜对了如果不对就调整拼接顺序或尝试SHA256。这种在抓包数据中做“变量消除”的推理过程是爬虫开发中最有成就感的部分。提醒一句当分析目标不是自己的产品时请先确认相关平台是否允许此类技术研究以及不要对加密算法进行破解传播。技术的价值在于理解不在于越界。4. 深入协议细节当常规抓包不够用的时候4.1 抓不到包的底层原因代理失效与流量旁路Charles这类工具依赖系统HTTP代理工作但很多App在代码里设置了Proxy.NONE直接不走系统代理。这种情况下Charles里只有一个CONNECT请求甚至什么都看不到。如果你在网络设置里明明配好了代理App却死活没流量考虑一下这个因素。真正的排查办法是用Wireshark看数据包。在电脑上开启Wireshark监听手机热点或电脑网卡过滤条件设为tcp.port 443就能看到App与服务器之间的原始TCP连接。这样做的好处是无论App走不走系统代理只要它联网就能被看到。坏处是数据是加密的你只能看到握手过程看不到业务明文。不过对于判断“请求有没有发出、连接卡在哪一步”来说已经足够了。4.2 WebSocket长连接怎么抓不少实时类应用的数据传输早就不是普通HTTP轮询而是WebSocket长连接。在浏览器开发者工具里Network面板会单独显示一条类型为WS的连接点击后进入Frames标签页可以看到它发送和接收的每一帧数据。对爬虫开发者而言如果发现页面的数据是WebSocket推送的就需要用Python的websockets库或者websocket-client库去模拟连接。WS模拟的难点在于握手阶段。打开开发者工具里的WS帧你会看到客户端发送的消息里常常包含一个动态生成的随机数或递增序号服务端也必须返回特定的连接Id。此时必须在抓包数据里找出这些字段的生成规则。好在大多数WebSocket消息都是JSON格式明文结构相对清晰照着格式拼接即可。这里分享一个小技巧抓WebSocket的包时在Frames面板里右键选择“Save frames to file”可以把一段时间内的所有帧导出成文本方便离线分析消息序列。4.3 请求体加密与签名算法从抓包到验证的思路当你在Charles里看到请求体是{data:9f86d081884c...}这类密文时常规的改参数方式就不管用了。此时要分两条路走一条是找到前端生成加密数据的代码在爬虫里用相同算法复现另一条是直接复用前端加密结果比如通过执行JS来生成密文。你可以在抓包时先做一个对照组实验正常请求一次把request body里的密文保存下来然后再触发一次同样操作结果发现两次密文完全不同。这通常意味着请求体含有时间戳或随机数。接下来就可以去前端代码里搜索加密特征比如查找MD5、AES、CryptoJS等关键词。很多网站的加密函数就明晃晃写在JS里只是压缩过格式化后可读性大幅提升。定位到加密函数后用Python复现时要注意字符编码。最常见的坑是字符串拼接顺序不同、排序规则不同、还有编码格式用了utf-8而不是gbk。我会把自己写的一个小脚本用来验证把抓到的请求参数重新跑一遍加密算法比对输出结果是否与Charles中的密文相同。相同说明逻辑对了不同就从拼接顺序下手一种种试。5. 抓包实战中的高频问题与排查方案5.1 只有CONNECT请求没有任何业务请求如果你在Charles中看到很多CONNECT api.xxx.com:443但点开后没有子请求说明HTTPS解密没有生效。检查是否勾选了SSL Proxying并添加了目标主机和端口。在Charles的Proxy - SSL Proxying Settings里勾选Enable SSL Proxying然后添加*表示所有主机或精确主机。另外如果客户端没有信任Charles根证书代理虽然建立了隧道但无法解密也会表现为只有CONNECT。5.2 手机上装完证书访问网站仍然报错iOS用户最容易踩的坑是只下载了证书描述文件却没在“证书信任设置”里手动开启完全信任。两步缺一不可。Android用户则要确认装的是CA证书而不是客户端证书而且Android 7以上系统对用户证书的限制可能导致部分App依然校验失败这时要么降级设备不推荐要么在系统层处理。5.3 抓包工具一开客户端网络就断这通常不是抓包工具的问题而是代理配置错误。手机连接代理后必须确保电脑端抓包软件处于监听状态且电脑防火墙没有拦截8888端口。还有一种可能是电脑开了多个代理类软件端口冲突比如Charles占着8888Fiddler也试图占8888后启动的那个会失败或自动切换端口而手机端还按原来的端口配置自然连不上。5.4 抓到内容被gzip压缩成乱码Charles和Chrome Network面板一般会自动解压gzip但如果用某些独立代理或直接从curl输出看可能是压缩内容。Python requests里设置headers{Accept-Encoding: identity}可以请求未压缩的内容或者在拿到Resp后调用resp.content由requests自动解压。调试时如果怀疑响应内容看不懂先看一下响应头里的Content-Encoding字段。现象常见原因优先级操作只有CONNECT没有子请求未开启SSL Proxying或未信任证书添加SSL代理规则重装证书手机完全无法上网代理IP/端口写错或防火墙拦截检查IP、端口与防火墙HTTPS提示不安全证书未安装/未完全信任按不同系统重走证书信任流程App一开抓包就闪退存在证书校验或代理检测改用Wireshark观察或从合法测试角度处理响应内容乱码压缩未解压关注Content-Encoding启用自动解压6. 抓包之外的爬虫工程化心得6.1 别把请求头直接硬编码进每一次请求里很多教程会在代码里写一大段headers字典Cookie固定死。这样做最大的问题是一旦服务端更新Cookie或加入新的校验字段整个爬虫就报废。抓包的意义是让你知道这些字段从哪里来而不是让你把快照焊死在代码里。我习惯用一个Session对象统一管理请求。requests.Session会自动保存服务端Set-Cookie下发的cookie并在后续请求中带上配合自定义的headers模板通常能省掉大量手工维护。import requests session requests.Session() session.headers.update({ User-Agent: Mozilla/5.0 ..., Accept: application/json, X-Requested-With: XMLHttpRequest, }) # 后续所有请求用 session.get/post resp session.get(https://api.example.com/list, params{page: 1})如果你的目标接口每次都需要从某个页面提取动态token那就把提取token的逻辑封装成一个函数在发请求前调用。抓包时多观察几次请求序列把这种“前置依赖”抽出来爬虫稳定性会提高很多。6.2 动手之前先做一次“双变量”比对所谓双变量比对就是在抓包工具中修改参数观察响应变化。比如把page1改成page2看看响应json里的数据是不是第二页。把请求头User-Agent删掉看看是否被403。把Cookie里的关键值去掉再看看响应是否变为登录跳转。这些动作能帮你快速判断服务端到底依赖哪些输入。很多时候反爬手段并非无懈可击只是你没找到关键字段而已。一个接口的参数可能很多但真正参与签名计算的往往只有三四个。排除无关参数最快的方法就是“删掉一个、比对一次”。6.3 抓包日志值得专门建设每次调试时在代码里顺手把请求的URL、状态码、耗时、响应摘要打印或落盘长期下来形成自己的抓包日志库。别小看这个习惯它帮我在排查定时任务半夜失败时节省了大量时间。只要看一眼日志里失败请求的URL和状态码基本就能定位是签名过期、IP被封还是字段缺失而不需要重新打开抓包工具对着一堆请求大海捞针。最后说点个人体会。抓包技术其实不是一门“功力”而是一套思维方式——每次看到一个动态数据先想它是哪个请求产生的每次看到一个请求先想它依赖哪些参数每次看到一个参数先想它从哪里生成。把这套“逆向式思考”练顺了Python爬虫写起来自然顺滑。反过来如果你只是复制一段代码跑通一次却看不懂请求背后的数据流那下次换个网站照样会卡住。所以别急着堆代理先把手头的包剖析透了你会发现大部分爬虫问题都出在“眼睛没看清”而不是“代码不够快”。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →