APP爬虫(UiAutomator2)

UiAutomator2

简介

背景

UiAutomator是Google提供的用来做安卓自动化测试的一个Java库,基于Accessibility服务。功能很 强,可以对第三方App进行测试,获取屏幕上任意一个APP的任意一个控件属性,并对其进行任意 操作,

但有两个缺点:

测试脚本只能使用Java语言

测试脚本要打包成jar或者apk包上传到设备上才能运

python-uiautomator2封装了谷歌自带的uiautomator测试框架,提供便利的python接口。他允许测 试人员直接在PC上编写Python的测试代码,操作手机应用,完成自动化,大大提高了自动化代码 编写的效率。

python-uiautomator2是一个自动化测试开源工具,仅支持Android平台的原生应用测试。

原理

在手机上运行了一个http rpc服务,将uiautomator中的功能开放出来,然后再将这些http接口封 装成Python库。

之前在电脑操作手机进行爬虫,基本上都是通过Appium的,这个工具确实强大,搭配谷歌官方的UiAutomator基本上可以完成各种爬取,但缺点也很明显,配置环境太麻烦了,需要jdk、sdk等,且在真机上安装的软件版本过低。

环境搭建

adb

安装adb 可以查看网上各种教程

UiAutomator2

安装python包 :

pip install --upgrade --pre uiautomator2 -i https://pypi.tuna.tsinghua.edu.cn/simple

weditor

安装python包:

pip install --pre weditor -i https://pypi.tuna.tsinghua.edu.cn/simple

这样环境已经搭建完成。

爬取基本流程

连接

将手机与电脑连接起来,总共两种方式,分别是:

Wifi连接


将手机wife与电脑wife连接到同一个wife下(同一个局域网)中,获取到手机的IP,并确保电脑可以PING通手机。手机的IP可以在设置-WIFI设置里面获取到。 

USB连接


将手机与电脑通过usb数据连接,在手机上选择本次调试的内容。

连接完成后最好将手机中UiAutomator2进程自启动关闭自动管理,以防止手机杀死UiAutomator2进程。

分析

打开weditor定位工具,在命令行中输入以下代码

# weditor
python -m weditor

浏览器中弹出一个界面,最好在无痕浏览器重新打开该页面,否则cookie残留可能会导致该页面报Local server not started, start with

输入设备号后,点击connect进行连接,成功后后面会显示一棵绿草,此时刷新一个界面Dump Hierarchy即可,如果你想实时刷新界面就打开实时按钮即可。

这里通过选中屏幕中元素,根据所展示属性(如xpath、text、location)等信息进行相关语法获取该元素。

代码

根据获得相关的信息和模块进行编写爬虫代码

uiautomator2连接设备
通过USB连接
import uiautomator2 as u2
d = u2.connect_usb('E6EDU20410023798')     # E6EDU20410023798就是在adb devices显示的序列号

通过WiFi连接
import uiautomator2 as u2
d = u2.connect('255.255.255.0')   255.255.255.0 为手机IP地址
打开app

         获得手机中app的包名和进程名(通过weditor等方式),执行以下代码,手机界面会跳转到指定的界面。

d.app_start('com.tencent.mm' , '.ui.LauncherUI') # app 和 活动
元素定位

        进行元素定位获取元素中数据。

常见定位依据

        ui2支持 android 中 UiSelector 类中的所有定位方式,详细可以查看官网:https://developer.android.com/reference/android/support/test/uiautomator/UiSelector,以下仅列出几种常见的定位依据:

依据描述

text

通过文本定位
textMatches通过文本正则匹配定位
className通过类名定位
classNameMatches通过类名正则匹配定位
description通过desc属性定位
descriptionMatches通过desc属性正则匹配定位
resourceId通过resourceId定位
resourceIdMatches通过resourceId正则匹配定位
子元素定位及兄弟元素定位

① 子元素定位-child

#查找类名为android.widget.ListView下的Bluetooth元素
d(className="android.widget.ListView").child(text="Bluetooth")
# 下面这两种方式定位有点不准确,不建议使用
d(className="android.widget.ListView")\
.child_by_text("Bluetooth",allow_scroll_search=True)
d(className="android.widget.ListView").child_by_description("Bluetooth")

② 兄弟元素定位-sibiling

d(className="android.widget.ListView", resourceId="android:id/list") \
  .child_by_text("Wi‑Fi", className="android.widget.LinearLayout") \
  .child(className="android.widget.Switch") \
  .click()
相对定位
d(A).left(B),# 选择A左边的B
d(A).right(B),# 选择A右边的B
d(A).up(B), #选择A上边的B
d(A).down(B),# 选择A下边的B
#选择 WIFI 右边的开关按钮
d(text='Wi‑Fi').right(resourceId='android:id/widget_frame')
Xpath定位

        Java uiautoamtor中默认不支持xpath,这是属于ui2的扩展功能,速度会相比其它定位方式慢一些。在xpath定位中,ui2中的description 定位需要替换为content-desc,resourceId 需要替换为resource-id

# 只会返回一个元素,如果找不到元素,则会报XPathElementNotFoundError错误
# 如果找到多个元素,默认会返回第0个
d.xpath('//*[@resource-id="com.android.launcher3:id/icon"]')
 
# 如果返回的元素有多个,需要使用all()方法返回列表
# 使用all方法,当未找到元素时,不会报错,会返回一个空列表
d.xpath('//*[@resource-id="com.android.launcher3:id/icon"]').all()
元素常用方法

方法

描述返回值备注

exists()

判断元素是否存在True,Flase@property
info()返回元素的所有信息字典@property
click()点击该元素
get_text()返回元素中文本字符串
set_text(text)设置元素文本None
clear_text()清空元素文本None
center()返回元素的中心点位置(x,y)基于整个屏幕的点
send_keys()发送文本        

        引用元素定位方法可以在源码中找到该元素定位方法类中拥有的方法。

设备交互

1)单击/双击
d(text='Settings').click()  # 单击
d.double_click(x, y)
d.double_click(x, y, 0.1) # 双击默认时间间隔0.1s

2)长按
d(text='Settings').longclick()  # 长按

3)滑动
# "left", "right", "up", "down"
d(text="Settings").swipe("up", steps=20)  # 元素向上滑动,步长20
d(text="Settings").swipe("down", steps=20)  # 元素向下滑动
d(text="Settings").swipe("left", steps=20)  # 元素向左滑动
d(text="Settings").swipe("right", steps=20)  # 元素向右滑动

4)拖动
d(text="Settings").drag_to(text="Clock", duration=0.25)  # 拖动到某个元素,时长0.25秒
d(text="Settings").drag_to(877,733)  # 拖动到屏幕某个坐标点,duration时长默认0.5秒
5)双指操作(元素放大/缩小)

d(text="Settings").pinch_in() # 缩小

d(text="Settings").pinch_out() # 放大
6)等待元素出现/消失
d(text="Settings").wait(timeout=3.0)  # 等待元素出现
d(text='Settings').wait_gone(timeout=20)  # 等待元素消失,返回True False,timout默认为全局设置的等待时间
 7)屏幕滚动
# 垂直滚动到页面顶部/横向滚动到最左侧
d(scrollable=True).scroll.toBeginning()
d(scrollable=True).scroll.horiz.toBeginning()
# 垂直滚动到页面最底部/横向滚动到最右侧
d(scrollable=True).scroll.toEnd()
d(scrollable=True).scroll.horiz.toEnd()
# 垂直向后滚动到指定位置/横向向右滚动到指定位置
d(scrollable=True).scroll.to(description="指定位置")
d(scrollable=True).scroll.horiz.to(description="指定位置")
# 垂直向前滚动(横向同理)
d(scrollable=True).scroll.forward()
# 垂直向前滚动到指定位置(横向同理)
d(scrollable=True).scroll.forward.to(description="指定位置")
# 滚动直到System元素出现
d(scrollable=True).scroll.to(text="System")

8)文本框操作
d.send_keys("test")

d.clear_text() # 清空输入框
9)toast操作
# 获取toast,当没有找到toast消息时,返回default内容
d.toast.get_message(timout=5,default='no toast')
# 清空toast缓存
d.toast.reset()

 10)监控操作
# 移除ANR的监控
d.watcher.remove("ANR")
 
# 移除所有的监控
d.watcher.remove()
 
# 开始后台监控
d.watcher.start()
d.watcher.start(2.0) # 默认监控间隔2.0s
 
# 强制运行所有监控
d.watcher.run()
 
# 停止监控
d.watcher.stop()
 
# 停止并移除所有的监控,常用于初始化

d.watcher.reset()

结合以上内容进行页面跳转,屏幕的滚动,可进行数据采集

  • 56
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值