以下基于
python3.8;airtestIDE1.2.13;airtest1.2.4;pocoui1.0.85

局部截图+找图

Airtest提供了全屏的找图API,wait()和exists(),可以看Airtest API精讲之wait(),exists()

为什么还需要局部找图呢,因为缩小查找范围找的更快啊。比如找一个App的图标,在1080*2340大小的图片找140*140的图标,肯定要比在140*140的图片上找140*140的图标,要慢的多。

下面演示一个实例:

  1. 局部截图小米"手机管家"App图标,并保存
  2. 10秒后,再次局部截图小米"手机管家"App图标,并保存
  3. 用第2次的截图去匹配第1次的截图,如找到则返回"手机管家"App图标在手机上的绝对坐标,方便click()等操作
# -*- encoding=utf8 -*-
__author__ = "测试工程师小站"

from airtest.core.api import *
from airtest.aircv import *

# 初始化,logdir为截图和日志存放路径
auto_setup(__file__, devices=["android:///"], logdir='/Users/szh/report/log')

# 第1次对手机截屏
screen1 = G.DEVICE.snapshot()
# 根据坐标进行局部截图,即图标左上角和右下角的坐标(坐标可以在AirtestIDE里获取)
screen1 = aircv.crop_image(screen1, (599, 156, 744, 302))
# 保存局部截图(清晰度99最高),保存成功后会返回文件名和截图大小
r1 = try_log_screen(screen1, quality=99)
# 打印返回,形如:{'screen': '1642500247024.jpg', 'resolution': (145, 146)}
print(f'r1:{r1}')

# 以上就完成了第1次局部截图,以上操作你也可以事先手动截图并保存,方便下面的直接对比。
sleep(10)

# 第2次对手机截屏
screen2 = G.DEVICE.snapshot()
# 局部截图
screen2 = aircv.crop_image(screen2, (599, 156, 744, 302))
# 保存局部截图
r2 = try_log_screen(screen2, quality=99)
print(f'r2:{r2}')

# 将第1次的局部截图设置为一个Template对象,如果之前是手动截取,那也在这定义一下
tempalte = Template(rf'/Users/szh/report/log/{r1["screen"]}')

s = time.time()  # 局部找图开始计时

# 在第1次的局部截图中匹配第2次的局部截图
pos = tempalte.match_in(screen2)

print(f"局部找图消耗时间:{time.time() - s}")  # 打印局部找图耗时

# 返回找到的图片坐标(该坐标是相对于局部截图的中心点坐标)
print(pos[0], pos[1])

# 若要返回目标在整个屏幕中的坐标,则需要加上局部截图时左上角的坐标
if pos:
    pos = pos[0]+599, pos[1]+156
    print(pos[0], pos[1])
else:
    print('没找到')

# 对比一下exists()全屏的找图时间
s = time.time()
exists(tempalte)
print(f"全屏找图消耗时间:{time.time() - s}")

运行后可以在指定的路径看到2次截图的图片。
可以看到局部找图比全屏找图快多了:

r1:{'screen': '1642501303079.jpg', 'resolution': (145, 146)}

r2:{'screen': '1642501303184.jpg', 'resolution': (145, 146)}

局部找图消耗时间:0.002668142318725586

72 73
671 229

全屏找图消耗时间:0.2622840404510498

图解一下上例中的坐标

airtest 获取图片 airtest局部截图_全屏

不过局部截图有个缺点,就是要指定绝对坐标,如果换了手机,就对不上坐标了。不过如果是相同分辨率比率的,可以通过相对坐标换算来兼容。不同分辨率比率,就把截图尺寸放大一些吧。

比如在100*100的屏幕上,坐标是[50,50],那相对坐标就是[0.5,0.5];在1000*1000的屏幕上该点坐标=[1000*0.5, 1000*0.5]

代码如下:

# -*- encoding=utf8 -*-
__author__ = "测试工程师小站"

from airtest.core.api import *

# 其他设备上获取到的相对坐标
relative = [0.5, 0.5]

# 获取当前手机的分辨率
if G.DEVICE.display_info['orientation'] in [1,3]:  # 竖屏时
    height = G.DEVICE.display_info['width']
    width = G.DEVICE.display_info['height']
else:  # 横屏时
    height = G.DEVICE.display_info['height']
    width = G.DEVICE.display_info['width']

absolute = [height*0.5, width*0.5]  # 绝对坐标

截屏另存为

正常情况下用例跑完后,生成报告,报告中就包含了运行中的各种截图,但如果你期望某些截图单独保存,以供将来对比等用处,可以这样做:

# -*- encoding=utf8 -*-
__author__ = "测试工程师小站"

from airtest.core.api import *
from airtest.aircv.utils import cv2_2_pil

auto_setup(__file__, devices=["android:///"])

screen = G.DEVICE.snapshot()  
pil_img = cv2_2_pil(screen)
pil_img.save("D:/qasite/测试工程师小站.png", quality=99, optimize=True)