1. 前言
前幾天有個新手同學在Airtest官羣裏問了這樣一個問題:我是新手,在圖片範圍內隨機點擊 ,用Airtest怎麼實現?代碼?那我們就以這個問題爲例,淺淺聊一下,怎麼把需求轉化成我們的Airtest代碼。
2. 瞭解Airtest
首先新手同學對Airtest要有以下幾點認知:- ① Airtest是一個圖像識別框架,它能在屏幕上用圖像識別來找到想操作的位置並點擊,所以Airtest本質上點擊的是目標圖片的座標,默認是中心點
- ② Airtest是python第三方庫,除了Airtest本身的接口之外,我們隨時可以import python的標準庫或者其它第三方庫,一起使用
3. 分析需求,轉化成代碼
1)查文檔,找現成方法
有了以上2點認知後,我們再回到需求,“在圖片範圍內隨機點擊”,第一步我們要做的就是查詢官方教程文檔,看下有沒有現成的方法可以使用:- ① 一般情況下,Airtest都是點擊圖片中心位置,不知道有沒有點擊圖片內其它座標的方法
- ② 隨機點擊,怎麼實現在圖片內隨機點擊這個行爲,不知道Airtest有沒有隨機點的方法
target_pos
,但是隻能點擊圖片內的9個點:
這裏似乎並不太符合在圖片範圍內隨機點的需求。隨後我們又查詢了文檔,發現Airtest也沒有提供隨機點擊的方法。
2)分析需求,自己實現
那麼我們到這裏就需要進入到第二步,分析需求,看看需求都有哪些難點需要我們實現:- ① 在圖片範圍內點擊,那意味着在整個圖片的座標範圍內點擊,那我們怎麼拿到整個圖片的座標範圍?
- ② 怎麼點擊一個隨機的座標?
random
了,能幫助我們生成一個隨機數的函數。
3)將思考轉化成代碼
最後一步就是將我們剛纔分析需求,得到的思路,轉化成代碼:# -*- encoding=utf8 -*-
__author__ = "AirtestProject"
from airtest.core.api import *
import random
auto_setup(__file__)
# 定義函數,得到目標圖片的座標範圍
def pos_range():
if exists(Template(r"tpl1697515204054.png", target_pos=1, record_pos=(-0.16, 0.154), resolution=(2960, 1440))):
up_pos = exists(Template(r"tpl1697515204054.png", target_pos=1, record_pos=(-0.16, 0.154), resolution=(2960, 1440))) # 利用target_pos=0,拿到目標圖片左上角的座標
down_pos = exists(Template(r"tpl1697515204054.png", target_pos=9, record_pos=(-0.16, 0.154), resolution=(2960, 1440))) # 利用target_pos=9,拿到目標圖片右下角的座標
x = (int(up_pos[0]),int(down_pos[0])) # 拿到圖片x座標的範圍
y = (int(up_pos[1]),int(down_pos[1])) # 拿到圖片y座標的範圍
return x,y
else:
print("目標圖片不存在")
# 分別拿到圖片x座標與y座標的範圍值
pos_r = pos_range()
x = pos_r[0]
y = pos_r[1]
# 在x、y的座標範圍內生成隨機數
x_range = random.randint(x[0],x[1])
y_range = random.randint(y[0],y[1])
# 點擊圖片範圍內任意座標
touch([x_range,y_range])
4. 優化版
以上是簡單的一個實現,效率不是最優。下面介紹一個更優的實現方案: Moty同學是通過在本地python環境安裝Airtest庫去進行Airtest自動化腳本編寫的,同時該腳本在AirtestIDE上是可以完美適配運行的。 我們先來看看Moty同學代碼的運行情況,可以看到通過生成隨機座標的形式,點擊圖片上的任意點,這裏用計算器去具象化,可以看到每次隨機座標可以點擊不同數字或者數字的不同位置,每次運行都可以獲得隨機的數字序列。看起來很厲害的樣子,我們應該怎麼去實現呢?讓我們來看看Moty同學的代碼吧~# -*- encoding=utf8 -*-可以看出來,在編寫代碼的時候,Moty同學將每一個步驟進行函數封裝後,可以減少二次查找的次數以及代碼冗餘,Moty同學的編寫思路很值得我們學習~
__author__ = "Moty"
from airtest.core.api import *
from airtest.cli.parser import cli_setup
from airtest.core.error import *
from airtest.core.settings import Settings as ST
import random
"""
獲取模板匹配的目標區域的矩形 這一部分實現參考 cv.py 中 loop_find 部分
: param : tpl 模板
: param : intervalfunc 沒有合適匹配時的回調函數
: return 最佳匹配的矩形區域(x1,y1,x2,y2)
"""
def rectangle(tpl,intervalfunc=None):
G.LOGGING.info("Try finding: %s", tpl)
start_time = time.time()
while True:
screen = G.DEVICE.snapshot(filename=None, quality=ST.SNAPSHOT_QUALITY)
if screen is None:
# 如果截圖爲空,則可能是屏幕鎖定了
G.LOGGING.warning("Screen is None, may be locked")
else:
match_result = tpl._cv_match(screen)
if match_result:
try_log_screen(screen)
# 這裏 rect 得到的是 4個座標點 取出左上右下角 得到(x1,y1,x2,y2) 元組
rect = match_result.get("rectangle")
if rect is not None:
return (round(rect[0][0]) , round(rect[0][1]) , round(rect[2][0]) , round(rect[2][1]))
if intervalfunc is not None:
intervalfunc()
# 超時則raise,未超時則進行下次循環:
if (time.time() - start_time) > ST.FIND_TIMEOUT:
try_log_screen(screen)
# 如果超時,則拋出異常
raise TargetNotFoundError('Picture %s not found in screen' % tpl)
else:
time.sleep(0.5)
"""
param : rect : 矩形區域 或模板
return : 區域內的隨機座標
"""
# 獲取矩形區域內的隨機座標
def random_point(rect):
# 如果傳入的是圖片,則獲取圖片匹配的矩形區域
if isinstance(rect, Template):
x1, y1, x2, y2 = rectangle(rect)
else:
x1, y1, x2, y2 = rect
# 在矩形區域內隨機生成一個座標點
x = random.randint(x1, x2)
y = random.randint(y1, y2)
return x, y
"""
在 矩形範圍內 隨機點擊
param : v : 目標區域 or 模板 or 座標點(兼容touch)
param : times : 點擊次數
return :最終點擊的點的座標
"""
@logwrap
def random_touch_in_area(v, times=1, **kwargs):
if isinstance(v, Template) or (isinstance(v, tuple) and len(v) == 4):
pos = random_point(v)
else:
try_log_screen()
pos = v
# 在目標區域內隨機點擊
for _ in range(times):
G.DEVICE.touch(pos, **kwargs)
time.sleep(0.05)
delay_after_operation()
return pos
if __name__ == '__main__':
# 如果沒有通過命令行連接設備,則使用該連接命令,若使用IDE運行則可忽略這段代碼,不用寫上
if not cli_setup():
auto_setup(__file__, logdir=None,
devices=["android:///",])
# 錄製圖片
tpl = Template(r"tpl1697636105500.png", record_pos=(0.243, -0.165), resolution=(1080, 2280))
# 獲取模板匹配的目標區域的矩形
result = rectangle(tpl)
print(f"圖片所在矩形區域 {result}")
# 在目標區域內隨機點擊
for i in range(10):
p = random_touch_in_area(tpl)
print(f"第 {i+1:02d} 次點擊座標 {p}")
sleep(1)
5.小結
最後,希望同學們在學習以及使用Airtest的時候,可以先學習方法,掌握代碼編寫技巧後,對自己的腳本可以進行優化再優化,從而實現代碼收益最大化。
---------------------------------------------------------------------------------
關注微信公衆號即可在手機上查閱,並可接收更多測試分享~