那天有个同事找我诉苦,说爬某个网站的数据快崩溃了。网站做了好几层加密,js混淆得亲妈都不认识,每次请求都要生成动态token。他折腾了一周,头发掉了一半,数据还是一片空白。我告诉他一个思路,他花了两小时就把数据拿下来了。这个思路就是从APP接口入手。
很多人一听到爬虫就盯着网页看,觉得APP是另一个世界的东西。实际上APP的接口往往比网页简单得多。网页为了保护用户浏览器里的数据,可以上各种反爬手段,加密、验证、风控系统一应俱全。APP的接口不一样,APP是安装在用户手机上的,服务器对APP的信任度天然高一些。很多APP直接走http明文传输,连SSL证书都不用管。数据就在那里放着,没人管你拿不拿。
抓取APP接口的逻辑很直接:你要做的是找到那个给APP提供数据的真实接口地址,而不是用户看到的那个花里胡哨的界面。APP的界面只是个壳子,数据从服务器到手机的过程才是关键。这个过程中间就藏着接口。
怎么找接口呢。先把手机连上电脑,用抓包工具拦截网络请求。我习惯用Fiddler或者Charles,免费又好用。设置好代理,把手机流量导向电脑。然后打开APP,随便点几个功能,看工具里跳出来的请求。排除掉图片、字体这类静态资源,剩下的就是数据接口。通常接口地址里会有api、v1、data这类关键词,一眼就能看出来。
重点看那些返回JSON格式数据的请求。网页爬虫最烦人的就是解析html标签,要一层层找class和id。JSON不一样,结构清晰,层级明确,直接用json.loads()就能解析成字典。数据字段的名字一般也是英文的,和中文功能对应得上。比如用户信息接口里会有username、phone这些字段,你甚至不需要打断点去查数据在哪。
有一次我爬一个外卖APP的数据。网页版做了图形验证码、滑块验证、请求签名,搞了三层加密。我转向APP后只用了两步。第一步,用抓包工具找到店铺列表的接口地址。第二步,看到返回数据只有店铺名称、评分、月销量这些字段,没有加密。接口甚至没做签名验证,直接拿数据走人。
APP接口的验证机制通常比网页弱。网页为了防止爬虫,会在请求头里塞一堆自定义参数,比如X-Requested-With、Referer、Origin。APP的请求头就简单得多,很多时候只需要一个User-Agent伪装成手机浏览器就能通过。有些APP甚至连基本的token验证都不做,直接裸奔。你只要把接口地址复制下来,写个requests.get()就能拿到数据。
当然也不是所有APP都这么耿直。有些APP会用protobuf序列化数据,或者把json用base64编码后再返回。遇到这种情况别慌,protobuf就找.proto文件反序列化,base64就解码一下。这些处理方式都有现成的Python库支持,网上搜一下就能找到解决方案。比网页上那些动态js加密要简单一百倍。
APP接口的请求频率限制也宽松。网页爬虫爬太快容易被封IP,APP不一样,手机用户是需要实时更新的。你几分钟刷一次数据,服务器觉得你是个正常用户。你每秒刷一次,它可能觉得你卡了。只要别太过分,没人搭理你。
写代码的时候记得模拟真实设备的环境。比如请求头里的User-Agent写成手机型号的字符串,比如iPhone或Android的设备信息。再带上一两个常用的请求头,像Accept-Encoding、Accept-Language这些。不需要花里胡哨的随机UA旋转,固定一个就好。太多随机反而容易被检测出异常。
APP接口的更新频率也比网页低。网页可能每周改一次页面结构,加密逻辑三个月升级一次。APP更新需要用户去应用商店下载新版本,改接口成本高,所以接口地址和数据结构一般能稳定半年以上。你写好的爬虫代码在这段时间内基本不用动,省心省力。
还有一个被很多人忽略的点:很多APP的数据在网页上根本没有。比如某些社区APP的私信聊天记录、某些电商APP的用户个性化推荐、某些社交APP的附近的人。这些数据网页不会展示,但你从APP接口里能直接拿到。
最后提醒一下技术之外的细节。抓取APP接口前确认一下该APP的用户协议和隐私政策。有些APP会在协议里明确写禁止爬取数据,有些则没提。虽然技术实现上可能没有障碍,但合规问题要自己把握。数据量大的时候注意控制请求频率,别把人家服务器打挂了。这不是技术问题,是做人问题。
我遇到的数据需求百分之八十都能通过APP接口解决。剩下百分之二十要么是接口太难找,要么是数据本身就不公开。换个角度看,当你还在为网页上的加密逻辑头疼时,不如试试APP接口这个更简单的办法。省下来的时间可以喝杯咖啡,甚至可以补补觉。
夜雨聆风