Appium 图像识别 OpenCV 解决安全键盘输入密码问题

深圳-Max · 2017年07月26日 · 最后由 yyy 回复于 2017年11月03日 · 658 次阅读

问题描述

支付场景中常常遇到安全键盘的问题,app 自动化无法抓取,而且键盘随机变化,每次都不一样。
自动化测试场景中必须要点击安全键盘比如:

解决思路

网上查找了一下比较稳妥的有两种方法:

  1. 图像识别,然后点击坐标
  2. 开发配合,给特定的 app 包,解除安全键盘

我选择了自己解决,毕竟找开发还有愿不愿配合的问题。。。
图像识别找到了 OpenCV 里面有 matchTemplate 方法,可以在图片中找指定的图片
简直完美了,那就开干吧

  1. 每个需要操作的位置进行截图并保存起来,切记按原图大小截取,尽可能小,比如:
  2. 然后就是在截取的屏幕上面查找这些数字对应的位置
  3. 按照位置在屏幕上点击

实现代码

以需要输入密码为例,我写了如下代码,需要传入截屏图片路径,还有需要输入的密码。
前面我们已经将各个数字的图片保存在本地,并以 n0.jpg, n1.jpg ... 保存,并和脚本放在一起。

我使用的 python 写的脚本,当然你还需要安装 OpenCV, 下载路径:http://opencv.org/releases.html
下载后把 build 下面的 python 里面的 cv2.pyd 文件复制到 python 目录下的 Lib\site-packages 里面

import cv2
import os
import numpy as np
import time

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('D:\test\img\sekeyboard.png', '123456')
    print(ls)

上面代码实现了获取每个数字的坐标,并以列表返回。
拿到坐标后面就可以直接操作了

执行效果:

代码不一定严谨,欢迎指正。

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 13 条回复 时间 点赞

使用这个方法识别一张小图,平均需要多少 ms?

多分辨率适配是个问题..

棒👍!谢谢 share!

不知道有没有人研究过 java + OpenCV 的

这个很不错啊,不知道能不能进行验证码的识别

JamesChung 回复

一个基本在 400 毫秒左右

深圳-Max 回复

好的,谢谢

这个推荐使用 OCR 来识别 或者 使用 OpenCV 的特征匹配 ,模板匹配在不同分辨率下效果比较差。

渐次消逝 中国工商银行 App 登录自动化实现 中提及了此贴 09月29日 10:17

@xiaoMGitHub 我用这个办法,可以识别出图, 得到坐标. 但是我感觉这个坐标不对..因为用 self.driver.tap([(坐标)], 20)点击没效果..应该是没点到目标地方.
是不是识别出所在图片的坐标, 和我在运行自动化用例的 app 上坐标, 还要做一个转换呢?


更新: 我试了一天,发现用 cv2 找的坐标, x 和 y 都除以 2, 就可以点击到我模拟器上的按键了...不知道为什么这里是要除以 2 呢?

yyy 回复

除以 2 是获取中心坐标,我用 java 的也是进行了处理才能用

渐次消逝 回复

哦..受教了...谢谢~

1楼 已删除
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册