前言:

随着移动互联网的兴起,国内早已是APP的天下,虽然主流的大厂都有web端,但是不可否认,很多好数据只有APP端才有。

本文只为多提供一种可能,萝卜咸菜,各有所爱。

天下武功,唯快不破:

工欲善其事,必先利其器,对工具的选择就是对效率的选择。

久闻Appium大名,但是经过上手一番才发现,并没有描述的那么美好,启动appium就得十几秒,偶尔还会报错、定位缓慢、操作都是重量级等等。。。

Appium还需要配合 Java SDK 与 Android SDK,安装安卓SDK甚至还得安装Android studio(尽管也可以不安装,但是我相信,大多数教程还是教你安装)。

那么?如题?到底能不能像解析网页一样解析APP页面呢?答案是:从某种意义上来说是可以的!

道,可道:

Appium定位方法比较多,比较常用的有通过布局id定位,或者xpath定位。而我们如何查看APP当前的布局信息呢?

方法很多,appium自带和Android studio中都是用到了UI Automator这个工具。

事实上,安卓系统中自带的就有uiautomator这个工具,我们可以利用adb执行它的dump命令导出当前的布局文件,然后利用lxml库分析元素位置等信息。

小试牛刀:

首先window用户可以移步至https://adbshell.com/downloads,下载adb工具并配置好环境变量。

https://lookcos.cn/usr/uploads/2020/08/2020082916180868.png

接着跟我执行如下命令:

# adb连接安卓,(mumu模拟器默认的地址与端口)      

adb connect 127.0.0.1:7555

# 利用uiautomator工具的dump命令,将当前app界面的布局文件导出至sdcard 下,保存在ui.xml文件中  

adb shell uiautomator dump /sdcard/ui.xml

#接着把文件导出到电脑本地

adb pull /sdcard/ui.xml E:\ui

打开可能会发现都在一行,不利于阅读,我们用在线工具美化一下:

https://lookcos.cn/usr/uploads/2020/08/202008291630366.png

不难发现,resource-id,text、class这些都出来了。

雄关漫道真如铁,而今迈步从头越:

到了这一步熟悉了吧,祭出我们的lxml库来解析出我们想要的数据,取出对应元素的 bounds值,我们就能获得该元素的坐标,进而点击它。如,bounds="[198,127][292,164]",这个bounds表示的是该元素的块区域坐标。

python 使用lxml解析ui.xml

from lxml import etree

xml = etree.parse("ui.xml")
soup = xml.getroot()
res = soup.xpath('//node[@text="热榜"]')[0]
print(res.get("text"), res.get('bounds'))

 #对应的node <node index="0" text="热榜" resource-id="" class="android.widget.TextView" package="com.coolapk.market" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[218,127][272,164]" /></node>

这是我获取酷安首页的布局文件,下面是打印结果:

https://lookcos.cn/usr/uploads/2020/08/2020082917115632.png

短短几行熟悉的代码,我们就获得了bounds的值,也即是 热榜这个对应的坐标范围:

https://lookcos.cn/usr/uploads/2020/08/2020082917140642.png

通过实际查看发现,确实是在这个范围内。

我们来写一个函数,解析它,并返回一个合法坐标

import os
import time
import random
from lxml import etree

os.system(r"adb connect 127.0.0.1:7555")
os.system(r"adb shell uiautomator dump    /sdcard/ui.xml")
time.sleep(2.5)
os.system(r"adb pull /sdcard/ui.xml E:\ui")

#解析bounds
def parse_bounds(bounds):
    bounds = bounds.replace("[", " ").replace(",", " ").replace("]", " ").replace("  ", " ").strip(" ").split(" ")
    x = random.randint(int(bounds[0]), int(bounds[2]))
    y = random.randint(int(bounds[1]), int(bounds[3]))
    return str(x), str(y)

xml = etree.parse("ui.xml")
soup = xml.getroot()
res = soup.xpath('//node[@text="热榜"]')[0]
x, y = parse_bounds(res.get('bounds'))
#点击
os.system(r"adb shell input tap {0} {1}".format(x, y))

上动图演示:

结束语:

实际的应用中还是很有用的,比如抖音此类搜索结果,不同的关键词有不同的视频量,有一些关键词我们需要扒拉几百下,而有的关键词只需要几下。

这个时候我们就可以通过这种方式来判断当前页面是否出现了“没有更多了”诸如此类的字眼。

看看,根据id、描述、text等信息定位并不难,而且效率与稳定性更是没得说。

本文仅作为演示,算是提供一种思路吧!
[toc]

标签: 自动化测试, Android, APP爬虫

相关文章

添加新评论