开开心心爬APP,结果一坑连一坑

2020-06-04 11:15:43 浏览数 (1)

本文来自「凹凸数据」读者投稿

大家好,我是新人三筒。

作为凹凸的铁粉,我会经常在历史消息里挖坟寻找我需要的教程。

最近因为业务需求,而要爬的数据又刚好没有对应的网页版,使我对手机爬虫教程格外感兴趣,一顿操作之后我发现,在这个过程中我遇到了一些回避不了的坑,需要跟大家分享一下。

前文回顾

回顾一下这篇文章用Fiddler篇爬取APP的教程:抓包手机大致分为以下几步

  1. 安装软件,设置软件。同时在电脑上安装证书
  2. 用手机连上和电脑相同的WIFI后,手机端设置代理。
  3. 手机端安装证书,信任证书。
  4. 打开抓包软件,刷新手机数据,观察并查找对应url。

一般来说,照这几个步骤是能够很顺利的取到数据。但是总有人脸黑,比如我。无论是用Fiddler还是Charles,都只能打开浏览器和高德地图。而打开知乎,小红书,好好住等APP却一律被拒绝访问。(oppo和小米手机都尝试过。)

尽管并非所有人都会踩到这个坑,但是这种进行到90%却突然卡住的感觉真的非常膈应人,查了好几篇博客,比较靠谱的说法是:Android7以后,APP一般不信任用户自己安装的凭据,也就是我们在手机上安装的抓包软件证书。

解决方法有两个:

  • 方法一,用Xposed拦截对证书的验证。
  • 方法二、把Fiddler/Charles的证书放进系统的证书目录里。

第一种方法仍然有坑,手机能检测到xposed拦截终还是会失败(这里我没有验证过,有兴趣的同学可以试试)。所以我选择planB,这里写下我的过程,作为一份补充参考给大家。

Charles的配置与步骤

在正餐开始之前,我简单说下Charles的配置(和Fiddler一个逻辑。只是界面稍有不同,选择用Fiddler的同学可以跳过这里直接看后面)

Charles的配置

1、软件安装基本上就是一路Next,装好以后进入主界面,进行如下设置:

Proxy》SSL Proxying Settings》Location中Add上Host:*,Port:*

ProxySettings》Proxies》Port设置为8888(总之手机代理上的端口号要与之相同)

2、在PC端安装证书,放置到受信任的机构。

Help》SSLProxying》InstallCharlesRootCertificate

3、打开手机的浏览器,输入弹窗中提示的链接chls.pro/ssl,下载证书安装。

好了,到这里重点来了!

同学们,如果你该勾选的选项也勾选了,该安装的证书也安装了,端口和代理配置都么有问题,以及最重要的是,如果你在电脑端能抓到数据,手机APP却拒绝访问。

别怀疑,你一定是碰到和我一样的坑了:你的手机APP不信任你安装的Charles/fiddler证书。我们需要想办法把它放到系统证书目录中去。

正餐开始。

当然,在开始之前,你需要准备:

  1. 一台root过的安卓机(最好是备用机,我用的是小米)
  2. Charles或者Fiddler的证书文件(Charles是crt文件,Fiddler是cer文件,后面获取hash值的时候会有差别)
  3. Windows系统需要下载安装openSSL工具(官网:https://www.openssl.org/,安装完后记得把openssl下的bin文件夹目录加入到环境变量中去)

好了,开始我们的操作!

step1

手机端下载证书后先别着急安装,导到电脑上,复制下它的路径(比如我的是"D:证书charlesgetssl.crt")

step2

按Win R,输入cmd,进入命令窗口,输入:

代码语言:javascript复制
opensslx509-subject_hash_old-in"D:证书charlesgetssl.crt"

记得in后面修改为自己的证书路径。执行后我们得到以下内容:

红色的这串就是我们获取到的证书的hash值,这个Hash值记得保存下来。Fiddler的证书由于是cer格式是无法直接获取的,需要先导成crt格式,我会在最后补充

step3

把证书修改成hash值.0格式。如下,别带后缀:

step4

将重命名好的证书放进手机的sd卡,记得复制进去的证书不可以有.crt或者.cer这样的后缀,以.0结尾才对。

step5

把改好名字的证书文件复制到系统的证书目录里,层级稍微有点深,路径如下(我这是小米的路径):

这里就会有个问题出现。直接用系统自带的文件管理器查看的话可能会获取不到完整的system文件目录,建议下载一个RE文件管理器,并且在安全中心里给予它root权限。如下(各品牌手机可能不同):

最后,重启下各类应用,就可以抓取了!

Fiddler的配置与源码

上面都是在说Charles,我们再讲讲Fiddler。

Fiddler的配置

其实Fiddler也是同理,需要我们获取到证书的Hash值,修改证书名后放进系统证书目录。只是因为Fiddler的证书是cer格式,我们需要多一个步骤:先把证书转成crt格式的。

同样是Win R后输入cmd进入命令窗口。cd到你放置证书的目录,然后输入转换格式的命令。如下(记得你的文件在哪个盘就输入哪个盘,在哪个目录就输入哪个目录):

代码语言:javascript复制
d:
cd Zhengshu
openssl x509 -inform DER -in FiddlerRoot.cer -out FiddlerRoot1.crt

此目录下就会生成一个crt格式的证书,然后我们继续用上面的方法读取它的hash值。输入:

代码语言:javascript复制
opensslx509-subject_hash_old-in FiddlerRoot.crt

得到我们想要的Hash值

再修改好名字放入系统证书后,我们就可以正常的抓数据了。最后我们以好好住这个APP为例,看看抓下来的数据是什么样的,我们以下面这个话题为例:

多滑动几屏,观察下哪个url是在闪烁的,这个多半就是我们要找的,或者直接从评论里摘取一段话,ctrl F搜索。这里我们发现是下评论内容都在下面这个url里。

也可以过滤一下监听的信息,在左下角的filter里设置成只监听该网址,看起来会更夹清爽:

好好住这个APP的数据是很清晰的json格式,我们只需要把对应的headers,cookies等参数加上,再写个循环,就能轻松把评论爬下来了。这些信息可以在右上角的窗口观察到,如下:

params参数如下,topic_id对应不同的话题(不过这个id并不是固定不变的,和我上一次观察的不同)

因为本文重点是如何突破APP的防备监听手机数据,这里我们就不详细展开写爬虫的逻辑。

爬虫源码

完整的代码如下。

代码稍微有点丑陋大家不爬这个APP的话可以不用看。

代码语言:javascript复制
#导入相关模块
import requests
import time
import random
#复制请求头,cookies等参数
headers={
    'user-agent':'Dalvik/2.1.0 (Linux; U; Android 8.0.0; MI 5 MIUI/8.11.22)hhz4.7.0-did44c043bb9672a88b4eafdfb3ce276c2c-h16946635abc3f22102c7e10-uid597199-ovid_1000000000597199-proxy-emu0',
    'accept-encoding':'gzip',
    'content-type': 'application/x-www-form-urlencoded',
}

cookies={
    'visitor_token':'ovid_1000000000597199',
    'hhz_token':'8ebae5a0dd1c47223a76243ce32f1347',
    'Token':'8ebae5a0dd1c47223a76243ce32f1347'
}
url='https://yapi.haohaozhu.cn/topic/GetAnswerList460'

remark_list=[]
for i  in range(1,28):
    #这个参数虽然又规律但是今天我看的时候已经发生变化了,大家如果要爬的话需要重新观察下。
    params='topic_id=365&sort_type=1&current_time=1589453251&page={}&basic_info={"$app_version":"4.7.0","$carrier":"其他","$lib":"Android","$lib_version":"1.6.19","$manufacturer":"Xiaomi","$os":"Android","$os_version":"8.0.0","$screen_height":1920,"$screen_width":1080,"distinct_id":"44c043bb9672a88b4eafdfb3ce276c2c"}'.format(i)

    #注意请求方式是POST
    res=requests.post(url,headers=headers,cookies=cookies,params=params)
    json_obj=res.json()
    data=json_obj['data']
    list=data['list']
    for content in list:
        #把评论文本提取出来
        comment_box=content['photo']['photo_info']
        comment=comment_box['remark']
        remark_list.append(comment)
        #加入停顿防止被反爬
        time.sleep(random.random())

脸黑的朋友们可以考虑下试试我的方法,也许能够解决困扰了你很久的问题。

0 人点赞