首页
社区
课程
招聘
[原创] 使用 Appium 进行安卓应用自动化“爬虫”
发表于: 2020-8-5 23:02 12429

[原创] 使用 Appium 进行安卓应用自动化“爬虫”

2020-8-5 23:02
12429

最近在做微信公众号采集的时候,延申出来一个需求,我要对公众号进行批量采集的话,势必需要先获取我自己关注的公众号列表,后面的自动化已经非常完整,所以只需要获取所有公众号的中文名称,整个流程就打通了。但问题来了,中文名称也不好搞哇。要不我手动一个一个输?列表拉下来一看,嗬,346个。我掐指一算,10秒一个,我得机械的在那儿打打打打字一个小时。不行不行,太要命了。

那就找找自动化的方法?微信现在PC端、移动端的接口都是铁板一块,像我这种工具小子,开个Fiddler毛都抓不到,毕竟人家也没用HTTP去通信。从通信角度肯定没办法了。一般这个时候我会想到Frida/Xposed,但现在的目标是微信,之前因为插件已经封过一个号了,需要获取数据的又是大号,不敢造次。因此只能去调研一下其他非侵入式的方法了。找来找去,在UI上做文章最为保险,本文就简单讲一下,如何利用应用自动化测试框架 Appium ,在非root环境的情况下获取任意安卓App界面上任意数据。

读者会有疑问了,前面我们说获取App界面上的数据,这应该是爬虫呀,怎么就跑到自动化测试上去了?其实这与安卓的内部机制有关。我们现在在做的事情是,从一个进程内控制另一个进程的运行方式。想要做到这一点,必然需要安卓系统提供API来支持。安卓提供了两个组件(至少是我在调研时想到的两个思路)可以实现这个需求,一个是为残疾人准备的 Accessibility 组件(用于屏幕阅读器、语音助手等等),一个是为测试狗准备的 UIAutomator 组件(用于单元测试)。

基于 Accessibility 的方案呢,现成的没有,找了一圈,都得写代码,既然都是写代码,我干啥不写Python呢?在 Reddit 上,有一个帖子提到了可以用 Tasker 配合一些杂七杂八的插件读取界面的内容,看网友的回复中,有一个插件也确实可以读取界面中的文本。但我感觉完成度还是比较低,在手机上用 Tasker 那个垃圾 GUI 完成剩下的功能……想想都挺拉胯的。而且 Tasker 还要钱,即使弄好了也没有写出来的价值,经验也不能复用。

基于 UIAutomator 的呢,随便搜搜就能找到一堆,比如 UIAutomator、Selendroid、Espresso等,Appium甚至都没排到谷歌的第一页上,最后选了 Appium 仅仅是因为我搜索关键字 微信 自动化 的时候,Appium 出现在其中一篇文章里了。可能大家都和我一样菜,只会写Python吧。

选择 Appium 有两大原因,说出来不怕害臊。一是,服务端(控制手机的host)有图形界面,下载个 exe 双击就启动了。二就是,客户端(调用API控制手机)可以用Python脚本,当然官方还支持 Java、JS、Ruby、C#、PHP 等各种语言,本质都是对服务器 REST API 的封装,看文档 一目了然。当然啦,它还有其他优点,比如 Appium 是 UIAutomator 、Espresso 的上层封装,在客户端上可以用参数指定到底用 UIAutomator 还是用 Espresso 作为 Driver,这些就留给读者自行探索啦。

Appium的架构分为服务端和客户端,服务端是一个缝合怪,在电脑上运行(支持Win/Mac/Linux),负责与设备(如安卓手机、或模拟器)通信,并把UI自动化接口通过 Web API 暴露出来。服务端从官方Github下载解压即可。但安卓调试还需要安装额外的依赖。

我的环境是 Win10 且安装了 chocolatey (一个包管理器),用下面一句命令可以装好所有依赖。

说白了,就是 Android SDK、adb 和 JDK 。

同时,需要确保 ANDROID_SDK_ROOTJAVA_HOME 环境变量正确设置。

上面步骤完成后,启动 Appium 程序,点蓝色大按钮启动服务就行了。

Appium主界面

下面我们就要写脚本获取微信公众号列表中的内容了。安卓应用的界面,在数据层面也是一个树状结构,实现上用 XML 表示,就像我们在写 Web 爬虫时需要处理的 DOM 树一样,而我们现在要获取一个应用某个界面下、某个组件中的数据,也可以通过 xpath 定位对应的组件,然后从实例里提取我们所需的信息。在 Chromium 里面我们有开发者工具,在 Appium 里呢?我们也有!

现在我们来启动一下 Appium 的“开发者工具”。Appium 的配置比较晦涩,主要是它搞了一大堆不明所以的名词,比如启动配置参数,在这里叫 Desired Capabilities 。

Desired Capabilities配置

我们在主界面里打开一个 Session Window 后,在 Desired Capabilities 的 JSON Representation 里面,输入以下的配置参数并保存。记得将 device id 替换成 adb devices 里显示出来的设备ID。非常关键的一点是,在任何情况下不要漏掉 noReset 这个参数。如果不加这个参数,默认会在每次启动 Session 时清除掉目标应用的全部数据!我一个微信号的聊天记录就这么被清理没了……

配置好参数以后,一样点击蓝色大按钮启动。此时 Appium 会强行 kill 掉并重启微信客户端,然后就可以用类似 Chrome 开发者工具一样的方式,用鼠标点击确认目标组件所在的层级结构了。

Inspector界面

以微信为例,我在这里选中的是某个公众号的名字,这个组件是个 TextView ,它的 resource-id 是 com.tencent.mm:id/a71 。尝试过后发现,列表中所有相同类型元素的ID都是一样的(比如“阿里云”这个标签和“敖厂长”标签的 resource-id 字段都是相同的)。

但很明显这是个混淆过后的 ID,而且应该会随微信版本更新而变化,这么搞不优雅。我们可以通过 XPath 来定位这个元素的位置,再动态获取它的ID,这样写了脚本就不怕微信更新了,一样能用。

经过一些尝试,我发现通过已知公众号名字来定位最为高效。最终我采用的表达式是 //android.widget.TextView[@text="阿里云"] 。通过这个表达式获取到 element,再通过这个 element 的 resource-id 即可获取到可视范围内所有的标签字段。

但还有一个难点,我提到了 可视范围内 ,每次获取最多也就能获取到一页,怎么翻页呢?

这里是我最终没有解决的一个难点。因为我遇到了两个问题。

一个是翻页这个 API 似乎在 Python SDK 里面他就没实现(虽然文档里写的是实现了),这就很糟心。最终的这个 API 和文档里也不一样,和文档里贴的 selenium API 也不一样。不一样你写它干啥??翻页不行我就模拟点击呗,结果模拟点击的步骤执行之间存在很大的延迟,我想实现的效果是,按下、拖动、松手,结果调用的时候,按下和拖动之间隔了有一秒还多,触发了微信菜单里长按操作的 context menu,无论如何无法解决。想换个Driver,结果又碰到了问题二。

二就是Espresso的实现似乎是基于Instrumentation的,启动的时候,花半天编译一个专用的apk出来,结果运行时报错,提示说被插桩的应用需要和源应用相同的签名证书。对于我们来讲这当然不可能实现了,签名证书如果可以伪造,我就可以写一个假冒的微信了。当然,签名伪造从 Xposed 层或者在 framework 做一些修改都可以实现,但我的主力手机连 root 都没有,所以也不折腾这些有的没的了。

Image

因此最终的妥协就是,每次识别完成以后程序 sleep 两秒,然后我手动拖动一下界面,还是很low的样子……

不过总结下来,代码量还是很小的,浓缩下来的精华也就三四十行。运行服务端以后,再运行这个 python 脚本就行了。

Image

最终结果,能用

Image

因为调研到实现的时间比较少,因此笔者对文中部分功能的实现原理还不是很了解,也就是能用。就这,我还是得说,从头到尾搞这玩意花了整整一晚上,还不如我一个一个输进去来得快呢。

原文首发于 个人博客 与公众号:rabyte

 
 
 
 

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

最后于 2020-8-5 23:03 被ttimasdf编辑 ,原因: 忘记删除hexo的标记了
收藏
免费 5
支持
分享
最新回复 (7)
雪    币: 19950
活跃值: (4942)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2020-8-6 06:57
0
雪    币: 181
活跃值: (2943)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3

自动关注,自动取关,自动点赞,自动聊天,自动xx
https://bbs.nightteam.cn/thread-86.htm

微X都还活着,没见怎么封,只是有一些【高风险】操作,别一直做就ok

最后于 2020-8-6 09:15 被huaerxiela编辑 ,原因:
2020-8-6 09:13
0
雪    币: 1867
活跃值: (3973)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
4
安利supperAppium项目
2020-8-6 10:21
0
雪    币: 1631
活跃值: (1364)
能力值: ( LV7,RANK:117 )
在线值:
发帖
回帖
粉丝
5
virjar 安利supperAppium项目
 找到项目了,之前另一位大佬给我推荐了一个类似的项目,我定睛一看原来就是基于你的项目写的  不愧是大佬.jpg
2020-8-6 14:17
0
雪    币: 209
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
感谢分享
2020-8-7 10:47
0
雪    币: 1636
活跃值: (653)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
7
aujs如何?
2020-11-18 08:17
0
雪    币: 453
活跃值: (129)
能力值: (RANK:0 )
在线值:
发帖
回帖
粉丝
8
现在的微信,都没几个搞得好的公众号了.
有的人,可能都做累了.不想做了.
2021-2-19 14:02
0
游客
登录 | 注册 方可回帖
返回
//