做爬虫这几年,我见过太多开发者在反爬对抗中走了弯路。有人只会用requests硬刚,结果IP被封得怀疑人生;有人只会用Playwright模拟浏览器,却不知道如何处理复杂的JS加密和APP反爬;有人学了Frida逆向,却不知道如何与其他工具配合提高效率。
我曾经为了爬取一个电商APP的数据,单独用Charles抓包花了一周时间,结果发现请求参数有动态签名,每次都会变;后来又用Frida逆向找到了签名算法,但是手动构造请求太麻烦,而且容易被检测;最后结合Playwright自动化,才终于实现了稳定高效的数据采集。
经过上百个项目的验证,我发现Charles+Playwright+Frida这三个工具的组合,几乎可以应对目前95%以上的反爬场景。它们各自有不可替代的优势,组合起来更是威力无穷。
今天我就把这套经过实战检验的工具链使用方法分享给大家,从原理到实战,再到踩坑经验,毫无保留。
一、为什么这三个工具是黄金组合?
很多人问我,反爬工具那么多,为什么偏偏是这三个?其实道理很简单:它们分别解决了反爬对抗中的三个核心问题,而且可以完美互补。
| 工具 | 核心优势 | 解决的问题 | 适用场景 |
|---|---|---|---|
| Charles | 强大的抓包分析能力,支持HTTP/HTTPS/Socket | 看清网络请求的全貌,找到加密参数和接口 | 所有需要分析网络请求的场景 |
| Playwright | 微软出品的浏览器自动化工具,反检测能力强 | 模拟真实用户操作,绕过前端渲染和行为检测 | Web端高反爬网站、需要登录和交互的场景 |
| Frida | 动态插桩工具,可以Hook APP和浏览器的JS代码 | 逆向加密算法,绕过反调试和证书校验 | APP反爬、复杂JS加密、反调试绕过 |
单独使用任何一个工具,都会有明显的短板:
- 只用Charles:只能看到请求,无法模拟复杂的用户行为,也无法逆向加密算法
- 只用Playwright:虽然可以模拟浏览器,但是遇到复杂的JS加密和APP反爬就束手无策
- 只用Frida:只能逆向算法,无法自动化执行和数据采集
只有把这三个工具组合起来,才能形成一个完整的反爬解决方案:用Charles抓包分析接口,用Frida逆向加密算法,用Playwright自动化执行和数据采集。
二、工具链整体工作流程
我画了一张工具链工作流程图,大家可以先有个整体的认识:
整个流程可以分为三个阶段:
- 分析阶段:用Charles抓包,分析目标网站/APP的网络请求,找到需要的接口和参数
- 逆向阶段:如果发现有加密参数,用Frida动态Hook,找到加密算法的实现
- 执行阶段:用Playwright模拟真实用户操作,结合逆向得到的加密函数,自动采集数据
下面我会详细讲解每个阶段的具体操作和技巧。
三、Charles:抓包分析的王者
Charles是我用过的最好用的抓包工具,没有之一。它的界面简洁,功能强大,支持HTTP、HTTPS、WebSocket等多种协议,而且可以很方便地修改请求和响应。
3.1 基础配置
首先是基础配置,这是很多新手容易踩坑的地方:
- 安装Charles:官网下载安装包,一路下一步即可
- 安装SSL证书:这是抓HTTPS请求的关键
- 电脑端:Help -> SSL Proxying -> Install Charles Root Certificate
- 手机端:电脑和手机连接同一局域网,手机设置代理为电脑IP:8888,然后访问chls.pro/ssl下载证书
- 配置SSL Proxying:Proxy -> SSL Proxying Settings -> 添加*.*,这样就可以抓所有HTTPS请求了
踩坑提醒:Android 7.0以上系统,用户安装的证书默认不受信任,需要把证书安装到系统证书目录。具体方法可以参考我之前的文章,或者用Xposed+JustTrustMe模块绕过。
3.2 核心抓包技巧
- 过滤请求:在Filter栏输入关键词,可以快速找到你需要的接口。比如输入"api"可以过滤出所有API请求
- 断点调试:右键点击请求 -> Breakpoints,可以在请求发送前或响应返回后中断,修改请求参数或响应内容
- 重发请求:右键点击请求 -> Repeat,可以重发请求,测试接口的响应
- 保存会话:File -> Save Session,可以把抓包结果保存下来,方便后续分析
3.3 反爬分析要点
用Charles抓包时,重点关注以下几个方面:
- 请求头:有没有特殊的头信息,比如
X-Token、X-Sign、Authorization等 - 请求参数:有没有加密的参数,比如
sign、data、timestamp等 - 响应内容:有没有加密的响应,比如返回的是Base64编码或AES加密的数据
- Cookie:有没有特殊的Cookie值,是怎么生成的
四、Frida:动态逆向的利器
当你用Charles抓包发现有加密参数时,就该Frida出场了。Frida是一个动态插桩工具,可以在不修改APP或网页代码的情况下,Hook函数的执行,查看参数和返回值。
4.1 环境搭建
- 安装Frida:
pip install frida frida-tools - 手机端安装Frida-server:下载对应手机架构的Frida-server,推送到手机并运行
adb push frida-server-16.1.0-android-arm64 /data/local/tmp/ adb shellsuchmod755/data/local/tmp/frida-server-16.1.0-android-arm64 /data/local/tmp/frida-server-16.1.0-android-arm64& - 测试连接:
frida-ps -U,如果能看到手机上的进程列表,说明连接成功
4.2 核心Hook技巧
我最常用的Hook技巧有以下几个:
Hook Java方法:
Java.perform(function(){varSignUtils=Java.use("com.example.utils.SignUtils");SignUtils.getSign.implementation=function(param1,param2){console.log("参数1:"+param1);console.log("参数2:"+param2);varresult=this.getSign(param1,param2);console.log("返回值:"+result);returnresult;};});Hook JS方法(浏览器端):
varoriginalSign=window.sign;window.sign=function(param1,param2){console.log("参数1:"+param1);console.log("参数2:"+param2);varresult=originalSign(param1,param2);console.log("返回值:"+result);returnresult;};主动调用函数:
Java.perform(function(){varSignUtils=Java.use("com.example.utils.SignUtils");varresult=SignUtils.getSign("test1","test2");console.log("主动调用结果:"+result);});
4.3 逆向加密算法的步骤
- 用Charles抓包,找到加密参数的名称和值
- 在APP的代码中搜索这个参数名,找到生成它的函数
- 用Frida Hook这个函数,查看输入参数和返回值
- 分析函数的实现,理解加密算法
- 用Python重写这个加密函数,或者用Frida RPC调用原函数
五、Playwright:自动化执行的核心
当你分析完接口,逆向完加密算法后,就该用Playwright来自动化执行了。Playwright是目前最好用的浏览器自动化工具,它的反检测能力远强于Selenium,而且API设计非常简洁。
5.1 基础使用
fromplaywright.sync_apiimportsync_playwrightwithsync_playwright()asp:# 启动浏览器browser=p.chromium.launch(headless=False)# 创建上下文context=browser.new_context()# 创建页面page=context.new_page()# 访问页面page.goto("https://www.example.com")# 点击按钮page.click("#submit")# 输入文本page.fill("#username","test")# 获取文本text=page.text_content("#title")print(text)# 关闭浏览器browser.close()5.2 反检测配置
这是Playwright最核心的部分,如果不做任何配置,很容易被网站检测到是自动化浏览器。
fromplaywright.sync_apiimportsync_playwrightwithsync_playwright()asp:browser=p.chromium.launch(headless=False,args=["--disable-blink-features=AutomationControlled","--no-sandbox","--disable-dev-shm-usage","--disable-extensions","--disable-gpu","--start-maximized"])context=browser.new_context(user_agent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",viewport={"width":1920,"height":1080},locale="zh-CN",timezone_id="Asia/Shanghai")# 注入JS,隐藏自动化特征context.add_init_script(""" Object.defineProperty(navigator, 'webdriver', { get: () => undefined }); Object.defineProperty(navigator, 'plugins', { get: () => [1, 2, 3, 4, 5] }); Object.defineProperty(navigator, 'languages', { get: () => ['zh-CN', 'zh', 'en'] }); """)page=context.new_page()page.goto("https://www.example.com")5.3 网络请求拦截
Playwright最强大的功能之一就是可以拦截网络请求,这在反爬对抗中非常有用。
defintercept_request(route,request):# 修改请求头headers=request.headers.copy()headers["X-Token"]="your_token"headers["X-Sign"]=generate_sign(request.post_data)# 继续请求route.continue_(headers=headers)page.route("**/api/**",intercept_request)结合我们之前用Frida逆向得到的generate_sign函数,就可以自动生成正确的签名参数,完美绕过接口校验。
六、完整实战案例:爬取某电商APP商品数据
下面我用一个完整的实战案例,展示如何把这三个工具组合起来使用。
6.1 需求分析
我们需要爬取某电商APP的商品数据,包括商品标题、价格、库存、图片等信息。
6.2 Charles抓包分析
- 打开Charles,配置好手机代理
- 打开电商APP,进入商品列表页
- 在Charles中找到商品列表接口:
https://api.example.com/v1/product/list - 查看请求参数,发现有一个
sign参数,每次请求都会变化 - 查看响应内容,是JSON格式,包含我们需要的商品数据
6.3 Frida逆向签名算法
- 反编译APP,搜索"sign"关键词,找到生成签名的函数:
com.example.utils.SignUtils.getSign - 用Frida Hook这个函数:
Java.perform(function(){varSignUtils=Java.use("com.example.utils.SignUtils");SignUtils.getSign.implementation=function(params){console.log("输入参数:"+params);varresult=this.getSign(params);console.log("签名结果:"+result);returnresult;};}); - 分析函数实现,发现是MD5加密,密钥是固定的:
"abc123" - 用Python重写这个函数:
importhashlibdefgenerate_sign(params):# 按照key排序sorted_params=sorted(params.items())# 拼接成字符串sign_str="&".join([f"{k}={v}"fork,vinsorted_params])+"abc123"# MD5加密md5=hashlib.md5()md5.update(sign_str.encode("utf-8"))returnmd5.hexdigest()
6.4 Playwright自动化采集
现在我们有了签名函数,就可以用Playwright来自动化采集数据了:
fromplaywright.sync_apiimportsync_playwrightimportjsonimporttimeimportrandomdefgenerate_sign(params):# 上面重写的签名函数importhashlib sorted_params=sorted(params.items())sign_str="&".join([f"{k}={v}"fork,vinsorted_params])+"abc123"md5=hashlib.md5()md5.update(sign_str.encode("utf-8"))returnmd5.hexdigest()defintercept_request(route,request):if"/product/list"inrequest.url:# 获取原始请求参数post_data=json.loads(request.post_data)# 添加时间戳post_data["timestamp"]=str(int(time.time()))# 生成签名post_data["sign"]=generate_sign(post_data)# 继续请求route.continue_(post_data=json.dumps(post_data))else:route.continue_()withsync_playwright()asp:browser=p.chromium.launch(headless=False)context=browser.new_context()page=context.new_page()# 拦截请求page.route("**/api/**",intercept_request)# 访问APP的H5页面page.goto("https://m.example.com")# 模拟用户操作forpage_numinrange(1,11):print(f"正在爬取第{page_num}页")# 滚动到底部加载更多page.evaluate("window.scrollTo(0, document.body.scrollHeight)")time.sleep(random.uniform(1,3))# 解析商品数据products=page.query_selector_all(".product-item")forproductinproducts:title=product.query_selector(".title").text_content()price=product.query_selector(".price").text_content()print(f"商品:{title},价格:{price}")# 点击下一页page.click(".next-page")time.sleep(random.uniform(2,4))browser.close()这样,我们就实现了一个稳定高效的爬虫,可以自动爬取10页商品数据。
七、进阶优化与踩坑经验
7.1 进阶优化技巧
- 使用代理池:配合代理池轮换IP,可以有效避免IP被封
- 使用指纹池:维护一个浏览器指纹池,每次请求使用不同的指纹
- 浏览器池化:创建多个浏览器实例,并发执行任务,提高效率
- 异常处理:添加完善的异常处理机制,遇到错误自动重试
- 数据去重:在采集过程中对数据进行去重,避免重复采集
7.2 常见踩坑经验
- Charles抓不到HTTPS请求:检查SSL证书是否安装正确,是否配置了SSL Proxying
- Frida连接失败:检查Frida-server是否运行,手机和电脑是否在同一局域网
- Playwright被检测:检查反检测配置是否完整,尝试使用不同的浏览器内核
- 签名算法逆向失败:尝试用Frida RPC直接调用原函数,而不是重写
- APP反调试:用Frida绕过反调试,或者使用Xposed+RootCloak隐藏Root环境
八、总结
Charles+Playwright+Frida这三个工具的组合,是目前反爬对抗中最强大的解决方案。它们各自解决了不同的问题,组合起来可以应对几乎所有的反爬场景。
在实际使用中,我们需要根据目标网站/APP的反爬强度,灵活选择工具和策略。对于简单的网站,可能只用Playwright就够了;对于有复杂加密的网站,需要结合Charles和Frida;对于APP反爬,Frida是必不可少的。
最后,我想强调一点:反爬对抗是一个不断升级的过程,没有一劳永逸的解决方案。我们需要不断学习新的技术,积累经验,才能在这场对抗中立于不败之地。
希望这篇文章能对大家有所帮助。如果有什么问题,欢迎在评论区交流。