手机自动化测试之图像识别——刷王者荣耀金币

  其实可以更简单实现刷金币的过程,可以参考:实现用python刷王者荣耀金币。这里使用图像识别进行刷取,更加稳定,但是也更复杂,这里主要是提供一个图像识别应用的思路。
一、关卡选取
  王者荣耀的冒险模式里有个挑战模式,第一次过关可以获得比较多的金币,后面重新挑战还是会获得少量金币,这不算是bug,只要你不嫌烦手动蛮力也可以刷金币。
  推荐关卡:堕落的祸源 - 稷下战场(大师)
在这里插入图片描述
  一把可以加56金币,大约一分多钟,在开挂前建议你手动通关体验一下,至少自动操作可以通关,此为游戏原理。不过挂机想通关稷下战场一般需要满符文,所以如果没有达到条件,可以刷:陨落的废都 - 魔女回忆,此关卡使用纯输出英雄20秒左右可以打BOSS,50秒左右可以通关,每次重复通关可以获得奖励19金币。
  测试的时候我用的英雄是:东皇,鲁班,扁鹊

二、操控原理介绍+第三方模块导入
  这里使用python-uiautomator2操控手机,只支持安卓手机,具体准备工作可以参考博文:手机自动化测试(准备篇)
  因为王者荣耀无法通过uiautomator2获取控件,所以本文思路是通过uiautomator2获取手机截图,接入腾讯OCR进行文字识别,并得到其文字位置,进而点击对应坐标并保存按钮截图,最后完成其按钮操作。以后的循环就只根据图像识别,进行模糊匹配获取当前屏幕信息,不再进行OCR识别。
  uiautomator2库本身带有OCR识别功能,但是并没有对应的API接口,需要自己找,于是从腾讯开发者里找到了文字OCR,结果发现并没有对应的python3SDK接口,真是坑,只好自己编个程序获取数据了,具体原理不细说了,不是本文的重点,有兴趣的可以看看,没兴趣的找到代码里appid,secret_id,secret_key自己更改一下,腾讯AI中心申请一个账号,在控制台能看到这几个变量,每个账号都有专属的ID。然后将下面的代码保存为tencentOCR.py文件,放到python路径里,作为第三方模块导入,后面要用到,如果python报错没找到该模块,就需要pip install [ packname],安装一下。

import requests
import hmac
import hashlib
import base64
import time
import random
import json

def TencentOCR(picture):
    appid = 'xxxx'
    secret_id = 'xxxx'
    secret_key = 'xxxxx'
    bucket = 'BUCKET'
    
    expired = time.time() + 2592000
    current = time.time()
    rdm = ''.join(random.choice("0123456789") for i in range(10))
    
    info = "a=" + appid + "&b=" + bucket + "&k=" + secret_id + "&e=" + str(expired) + "&t=" + str(current) + "&r=" + str(
     rdm) + "&u=0&f="
    
    signindex = hmac.new(bytes(secret_key,'utf-8'),bytes(info,'utf-8'), hashlib.sha1).digest() # HMAC-SHA1加密
    sign = base64.b64encode(signindex + bytes(info,'utf-8')) # base64转码,也可以用下面那行转码
    #sign=base64.b64encode(signindex+info.encode('utf-8'))
    
    url = "http://recognition.image.myqcloud.com/ocr/general"
    headers = {'Host': 'recognition.image.myqcloud.com',
       "Authorization": sign,
       }
    files = {'appid': (None,appid),
     'bucket': (None,bucket),
     'image': ('1.jpg',open(picture,'rb'),'image/jpeg')
     }  
    
    r = requests.post(url, files=files,headers=headers)
    
    responseinfo = r.content
    data = responseinfo.decode('utf-8')
    
    json_data = json.loads(data)
    datas = json_data['data']['items']
    recognise = {}
    for obj in datas:
        recognise[obj['itemstring']] = obj
    return recognise

if __name__ == '__main__':    
    beg = time.time()
    connect = TencentOCR(r'C:\Users\Administrator\Desktop\1.jpg')#图片路径
    end = time.time()
    print(end - beg)

  得到了文字的返回值,还要构造中心坐标,并进行点击,这里模仿uiautomator2-OCR原理,写了个程序,依然是作为第三方模块进行导入,有兴趣的可以看看,没兴趣的跟上个一样处理,其命名为:appmi.py。这里有一点要注意的是aircv依赖于cv2库,有个很坑的地方是,不能直接通过pip install cv2进行安装,而应该是pip install opencv-python,就可以安装了。

from PIL import Image
import time
import tencentOCR
import aircv as ac

class dxpath():
    def __init__(self,d):
        self.d = d
        
    def ocr(self):
        self.d.screenshot('screenshot.jpg')
        connect = tencentOCR.TencentOCR('screenshot.jpg')
        ocr={}
        for key in connect:
            lx, ly, rx, ry =connect[key]['itemcoord'].values()
            x, y = lx + rx//2, ly + ry // 2
            ocr[key]=(x,y)
        return ocr
    
    def ocr_click(self,char=None,timeout=10,at_once = False,repetition=1,
                  set_x=0,set_y=0,picture=False,picture_name='crop'):
    #char代表识别的字符串,timeout为响应时间,at_once为只判别一次,repetition代表重复点击次数
    #,set_x代表x坐标调整,picture是保存图像,picture_name为保存图片名
        deadline = time.time() + timeout
        while time.time() < deadline:  
            success = []
            self.d.screenshot('screenshot.jpg')
            connect = tencentOCR.TencentOCR('screenshot.jpg')
            for single in char:  
                try : lx, ly, rx, ry =connect[single]['itemcoord'].values() #优先精确查找
                except :                     
                    for key in connect:       #精确查找找不到的话查看是否包含在里面
                        if single in key :
                            lx, ly, rx, ry =connect[key]['itemcoord'].values()
                            break
                try : x, y = set_x + lx + rx//2, set_y + ly + ry // 2
                except : continue 
                for i in range(repetition) : 
                    if i != 0 : time.sleep(0.3)
                    self.d.click(x,y)
                success.append((x,y))
                if picture:
                    catIm = Image.open('screenshot.jpg')
                    croppedIm = catIm.crop((lx+set_x, ly+set_y, 
                                            lx+set_x+rx, ly+set_y+ry))
                    croppedIm.save('%s.jpg'%picture_name)
                if len(char)>1 :time.sleep(0.3)
            if success or at_once: break
        if not success : raise Exception("未找到控件")
        return connect , success   #connect是腾讯OCR发回的数据,success为点击坐标
        
    def locatonScreen(self,imgobj,confidence=0.9,click=True,imsrc=None):
        #imgobj待查找图片,imsrc为原始图像,默认为手机截屏
        if not imsrc: imsrc = ac.imread(self.d.screenshot('screenshot.jpg'))
        else : imsrc = ac.imread(imsrc)
        imobj = ac.imread(imgobj)
        match_result = ac.find_template(imsrc,imobj,confidence)
        if match_result is not None:
            match_result['shape']=(imsrc.shape[1],imsrc.shape[0])#0为高,1为宽 
            if click: 
                x,y = match_result['result']
                self.d.click(x,y)
        return match_result

三、好戏正式开始
完整的代码放到最后,下面一步步说明:
首先需要导入用到的第三方库

import threading
from appmi import dxpath
import uiautomator2 as u2
import time

定义刷金币的函数,并设置初始量

def shua(num=30,timer=113,wait=20):   
    #num为刷金币次数,timer随关卡时间调整,wait为最大等待次数

连接设备,在命令行输入adb devices获取设备号,例如我的手机设备号为:c00c166c,则代码如下:

	d = u2.connect_usb('c00c166c')  
	mi=dxpath(d)

构造点击函数,默认点击屏幕中心,每秒点击一次,这个主要是为了点击挑战里弹出的对话框。

	x2,y2 = [d.info['displayWidth']//2,d.info['displayHeight']//2]   #中心点
    def click(n):
        for i in range(n):
            d.click(x2,y2)
            time.sleep(1) 

每次程序的首次运行界面为
在这里插入图片描述
这样通过OCR识别出闯关的位置并得到其截图:

	comment,[(x1,y1)] = mi.ocr_click(['闯关'],picture=True,picture_name='chuang')  #闯关坐标  
	print('闯关按钮坐标:({},{})'.format(x1,y1))
	for i in range(10) : time.sleep(1)    #等待载入画面

在这里插入图片描述
获取再次挑战坐标:

    click(timer)    #随关卡不同可以更改时间
    for i in range(wait):
        try :comment,[(x3,y3)] = mi.ocr_click(['再次挑战'],at_once =True,
             picture=True,picture_name='tiaozhan')  ; break
        except : click(1)
    d.click(x3,y3)    #点击再次挑战按钮
    print('再次挑战按钮坐标:({},{})'.format(x3,y3))
    print('已刷第一次,获得金币56个')    
    for i in range(6) : time.sleep(1)   #等待加载页面

在这里插入图片描述
然后一直进行循环

    #进入循环
    jinbi = 56 
    for T in range(num-1):
        jinbi += 56
        for i in range(wait):
            if mi.locatonScreen('chuang.jpg') :break   #判定闯关是否出现,最大次数wait次
            time.sleep(1)
        d.click(x1,y1)
        for i in range(10) : time.sleep(1)
        click(timer)
        for i in range(wait):
            if mi.locatonScreen('tiaozhan.jpg') :break  #判定再次挑战是否出现
            click(1)
        d.click(x3,y3)
        print('提示:已刷第{}次,获得金币{}个'.format(T+2,jinbi))
        for i in range(6) : time.sleep(1)

做一个线程,不影响你运行别的python程序

扫描二维码关注公众号,回复: 11153536 查看本文章
threadObj = threading.Thread(target=shua)
threadObj.start()

下面给出完整程序:

import threading
from appmi import dxpath
import uiautomator2 as u2
import time
     
def shua(num=30,timer=113,wait=20):   
    #num为刷金币次数,timer随关卡时间调整,wait为最大等待次数
    d = u2.connect_usb('c00c166c')  #小米 MIX3
    mi=dxpath(d)
    def click(n):
        for i in range(n):
            d.click(x2,y2)
            time.sleep(1) 
            #print('已点击%s次'%(i+1))            
    comment,[(x1,y1)] = mi.ocr_click(['闯关'],picture=True,picture_name='chuang')  #闯关坐标  
    print('闯关按钮坐标:({},{})'.format(x1,y1))
    x2,y2 = [d.info['displayWidth']//2,d.info['displayHeight']//2]   #中心点   
    for i in range(10) : time.sleep(1)    #等待载入画面
    click(timer)    #随关卡不同可以更改时间
    for i in range(wait):
        try :comment,[(x3,y3)] = mi.ocr_click(['再次挑战'],at_once =True,
             picture=True,picture_name='tiaozhan')  ; break
        except : click(1)
    d.click(x3,y3)    #点击再次挑战按钮
    print('再次挑战按钮坐标:({},{})'.format(x3,y3))
    print('已刷第一次,获得金币56个')    
    for i in range(6) : time.sleep(1)   #等待加载页面
    #进入循环
    jinbi = 56 
    for T in range(num-1):
        jinbi += 56
        for i in range(wait):
            if mi.locatonScreen('chuang.jpg') :break   #判定闯关是否出现,最大次数wait次
            time.sleep(1)
        d.click(x1,y1)
        for i in range(10) : time.sleep(1)
        click(timer)
        for i in range(wait):
            if mi.locatonScreen('tiaozhan.jpg') :break  #判定再次挑战是否出现
            click(1)
        d.click(x3,y3)
        print('提示:已刷第{}次,获得金币{}个'.format(T+2,jinbi))
        for i in range(6) : time.sleep(1)
threadObj = threading.Thread(target=shua)
threadObj.start()
原创文章 27 获赞 24 访问量 2万+

猜你喜欢

转载自blog.csdn.net/u013289615/article/details/90608192