一、背景
先交代下背景,就是疫情期間,隨便玩了一款游戲,玩了后發現,游戲任務太繁重了,為了兼顧學習和游戲,所以就萌生了自己動手開發手游輔助外掛的想法,調研了幾個手機自動化測試平台最后選中了uiautomator2,然后有了這邊文章 《uiautomator2介紹及環境搭建》 以及文章《uiautomator2一分鍾實現輔助外掛》
如果仔細讀過第二篇文章的朋友就會發現,前面說的外掛就是 定時任務+ 模擬用戶點擊,如果碰上復雜點場景,就完全無法適應了,比如下面幾種
Boss有刷新又時間間隔,然后區分“野外”,”秘境“,”神諭“,每個刷新時間都不同,那么這個輔助腳本怎么寫呢,輪訓點擊肯定不現實,無法快人一步搶先刷到怪,怎么解決呢? 當然是如標題寫的 那樣,通過閱讀這篇博文,大家會了解到這些知識
- uiautomator2 截圖並裁剪
- python + tesseract 實現文字OCR識別
- tesseract 安裝及注意事項
- 以及帶大家看輔助外掛是如何一步步開發完成的。
博文可能略長,讀完可能需要點耐心。
另外鄭重聲明,本博客僅供繼續交流(因為畢竟是外掛嘛,這個自動刷掛功能,游戲里面包月要88元一月呢,所以大家懂得,源碼我就不開源共享了,但偽代碼下面都有的,更多大家可私下加QQ交流技術)
二、需求分解
要實現按時去刷怪,那么肯定需要上圖紅色框中那個刷新時間,這個文字又無法通過簡單的通過控件去識別,那么就只能通過圖片去實現了,我這里的思路是用網上開源的OCR文字識別庫識別出時間,到這里又不得不贊嘆python擴展能力真是強大,關鍵是拓展起來超級easy,不愧是“膠水語言”。好了,長話短說,文件OCR識別,我這里用的是tesseract,下面會介紹 tesseract 的安裝簡單使用。繼續我們剛剛的分解,假設可以通過圖片進行文字識別,那么要實現一個定時搶怪任務,我們需要的工作如下:
1、模擬點擊到刷怪頁面,並進行截圖
2、截圖到的圖片做裁剪(主要是過濾其他文字識別干擾)
3、對裁剪到的圖片做 灰度處理(比如彩色變黑白),然后二值化、降噪等一系列操作,主要是去除背景和一些其他的干擾。
4、識別到的數字轉化為秒,然后建立定時任務
5、定時啟動搶怪任務,截圖每個步驟圖片,拼接成一張圖,供人工查下結果。
6、截重復前面5個步驟實現自動刷掛打裝備
好了,下面我們一步步來實現這個效果。
三、腳本開發實踐
1、tesseract 安裝及測試
如果要使用Tesseract庫,首先需要安裝它到你的機器上。
macOS用戶,我們使用Homebrew 去安裝Tesseract:
$ brew install tesseract
當然有時候Homebrew 可能更新導致卡住,最簡單的辦法是在 .bash_profile 文件中新增一行,暫時關閉更新
export HOMEBREW_NO_AUTO_UPDATE=true
安裝完成后 tesseract -v 查看是否安裝完成
可以通過命令測試一把
比如下面一張圖片
我們通過命令 tesseract /Users/bifeng/222222.png stdout digits
可以看出一下子就把數字識別出來了,這里識別得是數字,如果是中文則需要改為
tesseract /Users/bifeng/3333.jpg stdout -l chi_sim
-l
后面得參數代表識別得語言 chi_sim
代表是中文簡體。
當然中文簡體字體是需要額外去下載字庫得,
去往https://github.com/tesseract-ocr/tessdata下載中文數據集chi_sim.traineddata,把它放到這目錄下:
/usr/local/Cellar/tesseract/對應版本/tessdata/
目錄下即可
更多Tesseract的介紹可以訪問GitHub 這里就不做過多發散了
2、python使用Tesseract庫識別文字
其實在很多場景中,都會有驗證碼環境,一般我們都是用 python + Tesseract來識別驗證碼,這里我們用來識別手游上倒計時也是“適得其用” 來,使用方式如下,首先安裝擴展庫
a、pip install pytesseract
用於python操作pytesseract
b、對要識別的圖片做降噪,簡單的說就是對圖片做簡單處理,如裁剪指定區域,過濾其他文字的干擾,做灰度化、二值化等一些操作,提供文字識別的准確性,具體代碼可以參見如下
!/usr/bin/python
#############################
# #encoding=utf-8
# bifeng 2020.03.23
# python tesseract 文字識別工具類
###############################
import pytesseract
from PIL import Image
class TesseractUtils(object):
@staticmethod
def imgae_to_str(image):
# 處理成黑白圖
image_gray = image.convert("L")
# image_gray.show()
# 進一步增強,使用二值化處理
image_two = image_gray.point(lambda x: 255 if x > 129 else 0)
#image_two.show()
# content = pytesseract.image_to_string(image) # 解析圖片
content = pytesseract.image_to_string(image_two, lang='chi_sim')
print(content)
return content
@staticmethod
def crop_image_to_str(image, left, top, right, bottom):
'''識別圖片部分區域位置'''
box = (left, top, right, bottom)
crop_img = image.crop(box)
# crop_img.show()
image_gray = crop_img.convert("L")
# image_gray.show()
# 進一步增強,使用二值化處理
image_two = image_gray.point(lambda x: 255 if x > 129 else 0)
#image_two.show()
content = pytesseract.image_to_string(image_two)
#識別中文
# content = pytesseract.image_to_string(crop_img, lang='chi_sim')
print(content)
return content
使用方法,通過通過調用api,可以識別指定區域圖片如:
TesseractUtils.crop_image_to_str(crop_img, 767, 289, 915, 334)
這里 767, 289, 915, 334 分別代表圖片區域 left, top, right, bottom 坐標如下面一張圖片
767, 289, 915, 334 剛好代表紅色框框區域,運行后我們可以得到
00:12:30 這樣一個時間 ,
3、構建定時任務,定時刷怪
轉換我們把它轉化為秒
def timeStr2s(t):
'''xx:xx:xx轉換為秒'''
if t is None:
return 10000
time = 10000
try:
h, m, s = t.strip().split(":")
time = int(h) * 3600 + int(m) * 60 + int(s)
except:
print("格式不對 : " + t)
return time
然后在建立定時任務
fristJob = TesseractUtils.crop_image_to_str(ywImg, 767, 289, 915, 334)
currSec = time.time()+ StringUtils.timeStr2s(fristJob)
tiemstr = time.strftime("%H:%M:%S", time.localtime(currSec))
LogEx.d("excuteJobList in " + tiemstr)
schedule.every().day.at(tiemstr).do(excuteJobList)
這樣一個定時刷掛任務就完成了,剩下的基本就是封裝刷掛,執行刷改,這里我是這么封裝的
#!/usr/bin/python
# #encoding=utf-8
# bifeng 2020.03.23
# 單步執行路徑
###########################
class CaseInfo(object):
def __init__(self):
# 用例名稱
self.name = ''
# 模擬執行列表
self.clicklist = []
# 單步執行休眠時間
self.sleepTime = 2
# 圖片裁取區域
self.cropBox = []
# 執行列表單步重復項
self.innerRepeatIndex = 2
# 默認循環次數
self.innerRepeatCount = 20
# 用例延遲多少秒后執行
self.excuteDelayTime = 30
name 代表名字
clicklist 代表執行路徑,比如一次野外任務,他有很多點,那么他的路徑就是如下:
case_table = {
'yewai0': [
# Boss坐標
(1028, 1321),
# 野外
(329, 1665),
# 第1個boss 885,406
(885, 406),
# 返回
(1009, 1831),
]}
self.innerRepeatCount = 20 代表,boss 挑戰按鈕 (885, 406), 這個我會循環執行很多變,保證我第一個按下,從而完成刷改功能,封裝好后,刷掛的代碼就很簡單了
def excuteJobList():
LogEx.v("----------excuteJobList start---------------------")
# global runner
runner = LegendRunner(adbConnectIp)
caseItem = caseList.pop()
LogEx.v("case list size = " + str(len(caseList)))
clickList = caseItem.getClickList()
LogEx.v("excute job " + caseItem.toString())
for index in range(0, len(clickList)):
LogEx.d("click : " + str(clickList[index][0]) + " " + str(clickList[index][1]))
runner.click(clickList[index][0], clickList[index][1])
if index == caseItem.getInnerRepeatIndex():
caseItem.setRepeatCount(90)
for i in range(0, caseItem.getRepeatCount()):
LogEx.d("click : " + str(i) + " " + str(clickList[index][0]) + " " + str(clickList[index][1]))
runner.click(clickList[index][0], clickList[index][1], 0)
time.sleep(0.4)
elif index == len(clickList) - 1:
timestamp = time.strftime("%H:%M:%S", time.localtime(time.time()))
LogEx.d("--sleep 80 s---------: " + timestamp)
runner.d.screenshot(os.getcwd() + "/image/" + timestamp + ".png")
time.sleep(80)
currSec = time.time() + 3
tiemstr = time.strftime("%H:%M:%S", time.localtime(currSec))
schedule.every().day.at(tiemstr).do(scheduleNextJob)
LogEx.v("----------excuteJobList end---------------------")
我只需要 for index in range(0, len(clickList)): 循環執行這個clicklist 就行了,然后在每個步驟下截圖一張,任務完成后把所有的圖片拼接成一張圖(如何拼接見文章《Python工具類之PIL.Image庫快速實現多圖拼接》)
執行完一個刷改任務,最后我們有建立下一個刷改任務
def scheduleNextJob():
LogEx.v("----------scheduleNextJob start---------------------")
global runner
# runner = LegendRunner(adbConnectIp)
# 獲取最近的boss定時任務
caseItem = runner.getRecentlyBossTask()
# 加入到任務列表
caseList.append(caseItem)
# 延時
currSec = time.time() + caseItem.getExcuteDelayTime() - 50
if currSec < time.time():
currSec = time.time() + 1
tiemstr = time.strftime("%H:%M:%S", time.localtime(currSec))
LogEx.d("excuteJobList in " + tiemstr)
schedule.every().day.at(tiemstr).do(excuteJobList)
LogEx.v("----------scheduleNextJob end---------------------")
掃碼到最近boss任務-》定時執行-》 執行完繼續掃碼下一個最近boss任務,這樣一直循環下去,就完成了一個簡單的自動定時刷怪任務。
4、最終效果
看下最終效果
刷怪過程中我們做了每個步驟的截圖,我們看下一次刷怪的效果截圖
這樣我們的腳本就開發完成了,剩下的只需要開啟腳本,喝上一杯茶,等上一段時候回來收獲刷怪掉落的神裝就可以了,是不是很爽,
“學以致用”感覺怎么樣。。因為畢竟是外掛的關系,為了避免法律風險,我不能直接提供源碼供大家下載,如果你有更多想法,大家可以私下交流,請加QQ群:1085210541