APP 自动化那些事儿:高效定位, 像解析网页一样定位 APP

2020-08-30 01:54:09 +08:00
 Austin2035

原文地址:

https://www.lookcos.cn/?p=816

前言:

随着移动互联网的兴起,国内早已是 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 工具并配置好环境变量。
接着跟我执行如下命令:


# 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

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

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

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

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

python 使用 lxml 解析 ui.xml

# -*- coding: utf-8 -*-

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>

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

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

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

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

# -*- coding: utf-8 -*-

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 等信息定位并不难,而且效率与稳定性更是没得说。

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

我的博客:

喜欢研究爬虫、web 等技术,欢迎来踩踩。
https://www.lookcos.cn/

2397 次点击
所在节点    分享发现
7 条回复
qq292382270
2020-08-30 03:11:43 +08:00
用了四年多安卓无障碍(AccessibilityService)开发自动化了,网上有好多高度集成的自动化产品了(例如 auto.js) ,学了几天发现还是自己用 java 写原生舒服...
itskingname
2020-08-30 07:29:40 +08:00
Appium 是出了名的笨重难用。你应该了解一下现代化的工具再来写文章。

用用看 Airtest

https://mp.weixin.qq.com/s/t4_OUPHh0qB0UV-6uGHq9g
Austin2035
2020-08-30 09:04:00 +08:00
@itskingname 你完整看一下文章再喷大哥,
我只是多提供一种思路。
你的公众号我有关注,没少洗稿!
lzlee
2020-08-30 09:50:08 +08:00
app 内嵌 h5 方便定位吗
Austin2035
2020-08-30 21:02:12 +08:00
@lzlee 纸上得来终觉浅,绝知此事要躬行
ttimasdf
2020-09-01 18:16:16 +08:00
楼主这个办法的确不用装一大堆东西,但实际进行应用分析的话,各种环境的安装还是必不可少的吧,合适的工具对提高分析效率也有很大的帮助。比如 Appium 自己也带了一个类似 Airtest 的 GUI 工具,我前一阵子也写过一个文章分享使用体验,还是蛮好用的(当然,当时我也不知道 Airtest,哈哈哈)

https://blog.rabit.pw/2020/appium-android-app-automation/
ttimasdf
2020-09-01 18:18:29 +08:00
@lzlee h5 就更好分析了呀,既然走 http 协议,抓包获取页面 html 内容,或者获取页面 URL 从电脑打开,和爬 web 页面的技巧是一样的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/702520

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX