1. 程式人生 > 實用技巧 >appium通過影象識別技術opencv解決無法定位

appium通過影象識別技術opencv解決無法定位

什麼時候我們需要用到影象識別?

問題1、在我們做 App 自動化測試的時候,會發現很多場景下元素沒有 id、content-desc、text 等等屬性, 並且有可能也會碰到由於開發採用的是自定義 View,View 中的元素也無法識別到,很多的自動化測試框架 對此類場景束手無策。問題2、在做自動化測試的過程中,遇到密碼鍵盤,需要進行模擬點選輸入的問題,使用appium提供的sent_keys方法不管用, 原因是密碼必須得點選密碼鍵盤進行輸入才能夠通過。密碼鍵盤的原理是每次點選一個按鍵,進行一次加密,點選結束後, 按登入才能夠登入通過。而send_keys的輸入方法是直接使用系統的鍵盤傳送鍵值到輸入框,沒有經過點選操作。密碼鍵盤的 一個難點就在於,它沒有id,而appium提供的定位方法大都是通過ID,name,class等元素進行頁面定位的,看過所有的定位方法後, 發現了通過座標值也可以進行定位,而密碼鍵盤要想定位成功,必須通過影象識別,識別出鍵盤所在的位置座標資訊。問題總結:通過傳統的Appium八種元素定位方式無法定位某些特殊場景下的元素,所以要通過影象識別的方式定位座標,最終實現模擬點選。

解決App密碼鍵盤無法識別問題的解決思路

這個問題的解決思路如下:1.針對iOS無序鍵盤:首先,iOS的密碼鍵盤是可識別的(和android區別),但是,密碼鍵盤一般是無序的。針對這個情況,思路是用Macaca或者appium-inspector來獲取到每個鍵的資訊的。首先,定義一個數據字典key_num={},把每個鍵的xpath儲存到字典裡面去。這樣key_num裡面儲存的就是key_num[0]="第一個按鍵的xpath路徑",key_num[1]="第二個按鍵的xpath路徑"以此類推,記錄完,整個鍵盤的xpath路徑。然後,通過xpath的值就可以取得該元素的name值,這個值就是該鍵的數字,取name值方式:物件.get_attribute("name")。然後,定義另一個字典keys_num={},來儲存每個按鍵對應的xpath和對應的數字。比如:第一個鍵是“6”,就寫keys_num[6]="第一個鍵的xpath",第二個鍵是“4”,keys_num[4]="第二個鍵的xpath",以此類推,記錄完整個鍵盤的數字和對應的xpath。這樣在輸入密碼的時候,只要遍歷密碼,例如:密碼是“666888”,那麼密碼的第一值是6,我們就取keys_num[6]的值就可以獲取到“數字6”的xpath,在通過get_element_by_xpath("數字6的xpath")方式就可以獲取到該元素,再用 元素.click()進行點選,就可以輸入該值了。2.針對Android無序且無法識別鍵盤
思路:通過影象識別方法對密碼鍵盤所在的座標進行識別。(利用opencv庫)所遇到的密碼鍵盤如下圖所示解決思路:1、影象識別,然後點選座標2、開發配合,給特定的app包,解除安全鍵盤。而對於非自己的app是無法使用第二種方法的。影象識別找到了opencv裡面有match Template方法,可以在圖片中找指定的圖片,步驟:1、首先需要操作的位置進行截圖並儲存起來,切記按原圖大小擷取,儘可能小,比如:2、然後就是在擷取的螢幕上面查詢這些數字對應的位置3、按照位置在螢幕上點選具體操作:(1、將需要進行影象識別元素所在頁面截圖(通過appium的driver是可以擷取當前螢幕的) 2、通過 adb pull 命令拉取截圖圖片出來 3、用畫圖工具開啟--劃重點,一定要保證圖片是原大小的,不能放大或者縮小圖片 4、擷取其中的元素儲存為圖片)實現程式碼:
以需要輸入密碼為例,我寫了如下程式碼,需要傳入截圖圖片路徑,還需要輸入的密碼。前面我已經將各個數字的圖片儲存在了本地,並以n0.jpg,n1.jpg,…儲存,並和指令碼放在一起。我使用python寫的指令碼,當然你還需要安裝opencv,下載後把build下面的python裡面的cv2.cp37-win_amd64.pyd檔案,放到python目錄下面的lib\site-packages裡面。程式碼如下。
#coding:utf-8
import os
import time
 
import cv2
import numpy as np
import matplotlib.pyplot as plt
 
def get_pay_keyboard_number_location(im, pwd):
    numbers = set(list(pwd))
    templates = {}
    positions = {}
    nimgpath = ""   #數字圖片不在同目錄時使用
    for i in numbers:
        templates[i]  = os.path.join(nimgpath, "n{}.jpg".format(i))
 
    start = time.time()
    img_rgb = cv2.imread(im)
 
    for teNum, tepath in templates.items():
        # print(tepath)
        template = cv2.imread(tepath)
        h, w = template.shape[:-1]
 
        res = cv2.matchTemplate(img_rgb, template, cv2.TM_CCOEFF_NORMED)
        threshold = .95    # 匹配度引數,1為完全匹配
        loc = np.where(res >= threshold)
        if len(loc) > 0:
            positions[teNum] = zip(*loc[::-1])[0]
        else:
            print("Can not found number: [{}] in image: [{}].".format(tepath, im))
 
    end = time.time()
    print(end-start)
 
    return [positions[n] for n in pwd]
 
if __name__ == "__main__":
    ls = get_pay_keyboard_number_location('keyboard.jpg', '1234567890')
    print(ls)
上面的程式碼實現了獲取每個數字的座標,並以列表進行返回。拿到座標後就可以直接的通過appium的tap,如
TouchAction(driver).long_press(x = 180,y = 1400).perform()
個人總結:注意在擷取圖片時一定要按原圖擷取。思路:利用opencv查詢部分圖片(擷取的),在整體圖片的座標,再利用座標進行點選。關於opencv庫的安裝可參考連結如下:https://blog.csdn.net/ningmengban/article/details/108545451?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param https://www.cnblogs.com/sophia201552/p/12893784.html
文章參考連結:https://blog.csdn.net/ningmengban/article/details/108545451?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-2.channel_param https://blog.csdn.net/jsqfengbao/article/details/77716101?utm_source=blogxgwz4&utm_medium=distribute.pc_relevant.none-task-blog-title-3&spm=1001.2101.3001.4242 https://www.cnblogs.com/baconLiu/p/6727845.html