其实可以更简单实现刷金币的过程,可以参考:实现用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程序
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()