airtest adb 远程连接_第八章 网易神器airtest:app版的selenium

265a1fb5e6c72bf4d7a90a5e2a52037f.png

简介

想开发网页爬虫,发现被反爬了?想对 App 抓包,发现数据被加密了?不要担心,使用 Airtest 开发 App 爬虫,只要人眼能看到,你就能抓到,最快只需要2分钟,兼容 Unity3D、Cocos2dx-*、Android 原生 App、iOS App、Windows Mobile……。

Airtest是网易出品的一款基于图像识别和poco控件识别的一款UI自动化测试工具。Airtest的框架是网易团队自己开发的一个图像识别框架,这个框架的祖宗就是一种新颖的图形脚本语言Sikuli。Sikuli这个框架的原理是这样的,计算机用户不需要一行行的去写代码,而是用屏幕截屏的方式,用截出来的图形摆列组合成神器的程序,这是Airtest的一部分。

另外,Airtest也基于poco这个UI控件搜索框架,这个框架也是网易自家的跨平台U测试框架,原理类似于appium,通过控件的名称,id之类的来定位目标控件,然后调用函数方法,例如click(),swip()之类的方法来对目标控件进行点击或者是操作。

爬虫开发本着天下工具为我所用,能让我获取数据的工具都能用来开发爬虫这一信念,决定使用Airtest来开发手机App爬虫。

官方文档 : http://airtest.netease.com/docs/docs_AirtestIDE-zh_CN/

## 关于自动化测试

概念:自动化测试,就是把繁杂的人工测试用例利用自动化测试工具编写成代码,让机器代替人工自动跑用例的过程。实际上就是把以人为驱动的测试行为转化为机器执行的一种过程。

意义:节省人力、物力、时间、硬件资源等,提升测试效率,特别对于繁琐重复的测试用例,可以使测试人员更专注于新的测试模块的建立和开发,从而提高测试覆盖率。

市面上常见的UI自动化测试工具以及优缺点

0ed1459a8cf252b28c009a57aea884c5.png

安装

由于目的是介绍如何使用Airtest来开发App爬虫,那么Airtest作为测试开发工具的方法介绍将会一带而过,仅仅说明如何安装并进行基本的操作。

安装Airtest 从Airtest官网:https://airtest.netease.com下载Airtest,然后像安装普通软件一样安装即可。安装过程没有什么需要特别说明的地方。Airtest已经帮你打包好了开发需要的全部环境,所以安装完成Airtest以后就能够直接使用了。

Airtest运行以后的界面如下图所示。

d47d3cb1ca848b054a044ee11dbea655.png

连接手机(打开开发者模式,以及USB调试模式)

以Android手机为例,由于Airtest会通过adb命令安装两个辅助App到手机上,再用adb命令通过控制这两个辅助App进而控制手机,因此首先需要确保手机的adb调试功能是打开的,并允许通过adb命令安装App到手机上。

启动Airtest以后,把Android手机连接到电脑上,点击下图方框中的refresh ADB,会在右侧显示侦测到的设备:

4334914c288bd138b6bfc242d058db4f.png

点击connect按钮,此时可以在界面上看到手机的界面,并且当你手动操作手机屏幕时,Airtest中的手机画面实时更新。如下图所示。

b7aaf338887a62b711989f35246b8b3f.png

对于某些手机,例如小米,在第一次使用Airtest时,请注意手机上将会弹出提示,询问你是否允许安装App,此时需要点击允许按钮。

知识

快速入门

先通过一个简单的例子,来看看如何快速上手Airtest,稍后再来详解。

例如我现在想使用电脑控制手机,打开应用商店。

此时,点击下图中方框框住的touch按钮:

f412be81df848164c8055c5a6bef3efb.png

此时,把鼠标移动到Airtest右边的手机屏幕区域,鼠标会变成十字型。在图标的左上角按下鼠标左键不放,并拖到右下角松开鼠标。此时请注意中间代码区域发生了什么变化,如下图所示。

1a58f268a08d27eee3412706579b2b7e.png

好了。以上就是你需要使用电脑打开应用商店所要进行的全部操作。

点击上方工具栏中的三角形图标,运行代码,如下图所示。

71f0929530a649e66c91f70e2abe0b97.png

代码运行完成以后,app被打开了。

打开应用

页面介绍

这里,我把Airtest分成了6个区域,他们的功能如下:

常用操作功能区 Python代码编写区 运行日志区 手机屏幕区 App页面布局信息查看区 工具栏

常用操作功能区是常用的基于图像识别的屏幕操作功能,例如:

d8adf2d00d1479304e5ee9f81786d44f.png

touch: 点击屏幕元素 swipe: 滑动屏幕 exists: 判断屏幕元素是否存在 text: 在输入框中输入文字 snashot: 截图 …… 一般来说,是点击A区里面的某一个功能,然后在D区屏幕上进行框选操作,Python代码编写区就会自动生成相应的操作代码。

Python代码编写区用来显示和编写Python代码。在多数情况下,不需要手动写代码,因为代码会根据你在手机屏幕上面的操作自动生成。只有一些需要特别定制化的动作才需要修改代码。

手机屏幕区显示了手机屏幕,当你操作手机真机时,这个屏幕会实时刷新。你也可以直接在手机屏幕区屏幕上使用鼠标操作手机,你的操作动作会被自动在真机上执行。

工具栏区是一些常用工具,从左到右,依次为:

新建项目 打开项目 保存项目 运行代码 停止代码 查看运行报告 其中1-5很好理解,那么什么是查看运行报告呢?

当你至少运行了一次以后,点击这个功能,会自动给你打开一个网页。网页如下图所示,这是你的代码的运行报告,详细到每一步操作了什么元素。

2a3966d099be63ea4ba799fe02f98613.png

基于App布局信息操作手机

初始化代码

App的布局信息就像网页的HTML一样,保存了App上面各个元素的相对位置和各个参数。对于一个App而言,在不同分辨率的手机上,可能相同的元素有着不同的坐标点,但是这个元素的属性参数一般是不会变的。因此,如果使用元素的属性参数来寻找并控制这个元素,就能实现在不同分辨率手机上的精确定位。

App的布局信息的格式与App的开发环境有关。点击页面结构区的下拉菜单,可以看到这里能够指定不同的App开发环境。其中的Unity、Cocos-*等等一般是做游戏用的,Android是安卓原生App,iOS是苹果的App……如下图所示。

e646c75e5b85068a2391ace750e5ed18.png

以手机版知乎为例,由于它是Android原生的App,所以在界面系欸狗区下拉菜单选择Android,此时注意python编码区弹出提示,询问你是否要插入poco初始代码到当前输入光标的位置,点击Yes,如下图所示。

904690b1f7af4e9fdde752378cb7ce73.png

此时,代码区自动插入了一段代码,如下图所示。

38089e2faa573afb0ad4ca683caf24eb.png

定位并点击

定位并点击

现在,点击界面布局区的锁形图标,如下图所示。

46fd28700d762b7bff4ae8e0182add30.png

锁形图标激活以后,你再操作手机屏幕区,点击知乎App下面的知乎两个字,会发现屏幕上被点击的App并不会打开。但界面布局区和日志区却发生了变化,如下图所示。

cfe6a4c86f449a7553f0ef38341f1207.png

其中界面布局区显示的树状结构就是当前屏幕的布局信息,这与Chrome开发者工具里面显示的HTML结构如出一辙。日志区显示的是当前被我点中的元素的信息。

请注意在这些元素信息中,有一个text属性,它的值为知乎。那么,这个属性就可以作为一个定位元素,于是可以在代码区编写代码:

poco(desc="知乎").click()

写完代码以后运行程序,可以看到知乎App被打开了。如下图所示。

b8ad0932cf8a893bc72f1c3941beee56.png

注意,如果你发现手机真机显示的界面与Airtest屏幕显示的手机界面不一致,可能是因为Airtest的屏幕被你锁定了。在F区点一下锁形图标,取消锁定,Airtest中的手机屏幕就会更新了。

定位并输入

打开知乎以后,我想使用知乎的搜索功能,那么继续,把锁形图标激活,然后点击知乎顶部的搜索框,如下图所示:

cd5af8bfa314f3d99f693b7923568291.png

继续看日志区显示的搜索框属性,可以看到这里有一个name属性,它的值是com.zhihu.android:id/input,还有一个text属性,它的值为用手机摄影 引爆你的朋友圈 。能不能像前面打开知乎一样,使用text这个属性呢?也行,也不行。说它行,是因为你这么做确实现在能工作;说它不行,因为这是知乎的热门搜索关键词,随时会改变。你今天使用这一句话成功了,明天热门关键词变化了,那么你的代码就无法使用了。所以此时需要使用name这个属性。

常见的基本上不会变化的属性包含但不限于:name type resourceId package。

另外还有一点,知乎首页的这个搜索框,实际上是不能输入内容的,当你点击以后,会跳转到另一个页面,如下图所示。

238bb2e8ce5766dcfd1f5af291b1e567.png

因此你需要先点击一下这个输入框,跳转到真正的搜索界面:

poco(name="com.zhihu.android:id/input").click()

然后再输入进行搜索:

可以看到,name属性的值依然是com.zhihu.android:id/input,此时就可以输入内容了。

输入内容使用的方法为set_text,用法为:

poco(name="com.zhihu.android:id/input").set_text('爬虫')

a44493a6acf354bc06c7e43981417ca5.png

运行查看效果

定位并筛选

输入了搜索关键词以后,再来看看当前页面,搜索出现了两个话题,六个提示:

654b5cf984521d2620de29bdd517f14d.png

通过对比这三个结果的属性信息,发现他们的name属性都是相同的,而text不同。如果像下面这样写点击动作:

poco(name='com.zhihu.android:id/magi_title').click()

那么默认就会点击第一个搜索结果。

如果我想点击第二个搜索结果怎么办呢?可以这样写代码:

poco(name='com.zhihu.android:id/magi_title', text='爬虫(昆虫)').click()

或者你也可以像列表一样使用索引定位:

poco(name='com.zhihu.android:id/magi_title')[1].click()

这两种写法的前提,都是我们已经知道了每个结果分别是什么。假设现在我就想搜索爬虫,但我不知道搜索结果是第几项,又应该怎么办呢?此时还可以使用正则表达式:

poco(name='com.zhihu.android:id/magi_title', textMatches='^爬虫.*$').click()

滑动屏幕

进入搜索结果以后,需要查看下面的各种问题,此时就需要不断向上滑动屏幕。这里有一点需要特别注意,Airtest只能获取当前屏幕上的元素布局信息,不在屏幕上的内容是无法获取的。这一点和Selenium是不一样的。

滑动屏幕使用的命令为swipe,滑动屏幕需要使用坐标信息。但这种坐标和屏幕分辨率无关。这里的坐标定义为:(x, y),其中x为横坐标,y为纵坐标。屏幕左上角为(0, 0),屏幕右下角为(1, 1),从左向右,横坐标从0逐渐增大到1,从上到下,纵坐标从0逐渐增大到1。

现在我要把屏幕向上滑动,那么在真机上面,我是先按住屏幕下方,然后把屏幕向上滑动,所以代码可以这样写:

#poco.swipe(起点坐标,终点左边)
poco.swipe([0.5, 0.8], [0.5, 0.2])

0c78f2c2f120d50df62d5f7bd52cf0f9.png

在一般情况下:

向上滑动,只需要改动纵坐标,且起点值大于终点值 向下滑动,只需要改动纵坐标,且起点值小于终点值 向左滑动,只需要改动横坐标,且起点值大于终点值 向右滑动,只需要改动横坐标,且起点值小于终点值

在爬虫开发中,涉及到的Airtest操作基本上已经介绍完毕。

获取app信息

既然要做爬虫,就需要获取手机上的文字内容。回到搜索页面,我想知道“爬虫”这个关键字能搜索出多少条结果,每条结果有多少个讨论,如下图所示:

此时我们需要做两件事情:

分别查看每一个搜索结果 获取屏幕上的文字 界面结构区的树状结构如下图所示:

c66f258bb5749c17b500fc789fa9682f.png

每一个搜索结果的标题作为text属性的值,在name='com.zhihu.android:id/magi_title'对应的元素中;每一个搜索结果的讨论数作为text属性的值,在name='com.zhihu.android:id/magi_count'对应的元素中。

最直接的做法就是分别获取标题和讨论数,然后把它们合并在一起:

title_obj_list = poco(name='com.zhihu.android:id/magi_title')
title_list = [title.get_text() for title in title_obj_list]

discuss_obj_list = poco(name='com.zhihu.android:id/magi_count')
discuss_list = [discuss.get_text() for discuss in discuss_obj_list]

for title, discuss in zip(title_list, discuss_list):
    print(title, discuss)

运行效果如下图所示:

0ed8e1f363605899712da56821df47ef.png

但是这种做法实际上是很危险的,假设会有某一个很生僻的搜索结果,只有标题没有讨论数,那么这样分开抓取再组合的做法,就会导致最后匹配错位。所以合理的做法是先抓大再抓小。每一组标题和讨论数,他们都有自己的父节点,如下图箭头所指向的android.widget.LinearLayout:

那么现在,使用先抓大再抓小的技巧,先把每一组结果的父节点抓下来,再到每一个结果里面分别获取标题和讨论数。 然而这个父节点又怎么获取呢?如下图所示,这个父节点每一个属性值都没有什么特殊的,写任何一个都有可能与别的节点撞上。 此时,最简单的办法,就是在界面结构区,双击父节点。定位代码就会自动添加。 这个定位代码看起来非常复杂,但实际上它的内在逻辑非常简单,就是从顶层一层一层往下找而已。

自动生成的定位代码如下:

poco("android.widget.LinearLayout").offspring("com.zhihu.android:id/action_bar_root").offspring("com.zhihu.android:id/parent_fragment_content_id").offspring("android.support.v7.widget.RecyclerView").child("android.widget.LinearLayout")[0]

在这个自动生成的定位代码中,我们看到了offspring、child这两种方法。其中child代表子节点,offspring代表孙节点、孙节点的子节点、孙节点的孙节点……。简言之,使用child只会在子节点中搜索需要的内容,而使用offspring会像文件夹递归一样把里面的所有节点都遍历一次,直到找到符合条件的属性为止。显然,offspring速度会比child慢。

实际上,我们可以对这个定位代码做一些精简:

poco("com.zhihu.android:id/parent_fragment_content_id").offspring("android.support.v7.widget.RecyclerView").child("android.widget.LinearLayout")[0]

这个精简的方法,与从Chrome复制的XPath中进行精简是一样的逻辑,根本原则就是找到“独一无二”的属性值,然后用这个属性值来进行定位。 由于我点击的是第一个搜索结果,所以定位代码的最后有一个[0]。现在由于需要获得所有搜索结果的内容,所以应该去掉[0]而使用for循环展开,然后获取里面的内容:

result_obj = poco("com.zhihu.android:id/parent_fragment_content_id").offspring("android.support.v7.widget.RecyclerView").child("android.widget.LinearLayout")
for result in result_obj:
    title = result.child(name='com.zhihu.android:id/magi_title').get_text()
    count = result.child(name='com.zhihu.android:id/magi_count').get_text()
    print(title, count)

运行效果和之前一致,但更安全。

单独使用Python控制手机

在Airtest操作手机虽然方便,但是不可能在每一台电脑上都安装Airtest吧。所以需要想办法把代码从Airtest这个程序中分离出来。

Airtest基于Python的一个开源库Poco开发,而在Airtest的B区写的Python代码,实际上就是Poco的代码。所以只要安装Poco库,就可以在Python中直接控制手机。

安装Poco库的命令为:

pip install pocoui

这个库依赖的东西有点多,安装稍稍慢一些。安装完成以后,我们把代码复制到PyCharm中,如下图所示。

be23c239270cdd53b304a090e8d476c9.png

常用api

  1. 路径 child:查找子节点,等同于xpath表达式 / offspring:查找子节点,等同于xpath表达式// children:查找子节点,等同于xpath表达式/*
  2. 动作 click:相当于selenium的click set_text:相当于selenium的send_keys swipe:相当于selenium的driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
  3. 访问属性 get_text:获取节点文本,等同于xpath表达式 /text() attr:获取节点属性,等同于xpath表达式/@属性名

任务

爬取饿了吗app商家信息

7cf016cf6211850389fb11663a4bb27b.png

爬取美团外卖app商家信息

6323b69a4fd199f242450218bacd498a.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值