最近和跟着同事一塊兒玩陰陽師,發現這個遊戲有太多重複操做了,這徹底就是浪費生命啊;因此想到用python寫一個自動掛機腳本。python
最開始想得很簡單,就是一直去找相應得按鈕,而後點擊就能夠了。因此直接用pyautogui的圖片定位和點擊功能就好了,也確實實現了,代碼以下:多線程
import pyautogui,time pyautogui.FAILSAFE = True '''PyAutoGUI提供了一個保護措施。當pyautogui.FAILSAFE = True時,若是把鼠標光標在屏幕左上角, PyAutoGUI函數就會產生pyautogui.FailSafeException異常,用於在程序失控時退出''' time.sleep(2) def get_point(picture): '''精確匹配某個按鈕的位置;經過傳入圖片獲取圖片在屏幕上的定位,一旦獲取到值則退出,不然繼續嘗試''' picture = './img/' + picture count = 5 while count > 0: point = pyautogui.locateCenterOnScreen(picture) if point is not None: return point else: count -= 1 def get_range(picture): '''用模糊匹配獲得某個按鈕的大概位置,通常是在那種點擊屏幕任意位置的狀況,或只須要知道某個按鈕在不在當前屏幕的狀況使用 要動的圖片採用模糊匹配,不然精確匹配的話,圖片一直在動像素也在變化,就不能定位到了''' picture = './img/' + picture count = 5 while count > 0: range = pyautogui.locateCenterOnScreen(picture, grayscale=True, confidence=0.5) if range is not None: return range else: count -= 1 def click_button(picture,accurate=True): '''點擊按鈕的函數,默認精確度爲True,即默認爲精確點擊,若是accurate=False,則爲模糊點擊,用於動態圖形按鈕''' if accurate==True: action = get_point(picture) else: action = get_range(picture) if action is not None: pyautogui.click(action,duration=0.5) def cycle_fight(): '''用戶循環重複的戰鬥場景,若是刷覺醒材料,刷御魂''' while True: click_button('tiaozhan.PNG') click_button('zhunbei.PNG') click_button('over.PNG') cycle_fight()
最後發現這樣彷佛不科學,不只慢還浪費資源;而後又想到在準備完成和戰鬥結束這段時間,有很長的空白期,徹底可讓程序中止啊,因此又出現了下面的代碼:
import pyautogui,time pyautogui.FAILSAFE = True '''PyAutoGUI提供了一個保護措施。當pyautogui.FAILSAFE = True時,若是把鼠標光標在屏幕左上角, PyAutoGUI函數就會產生pyautogui.FailSafeException異常,用於在程序失控時退出''' time.sleep(2) def get_point(picture): '''精確匹配某個按鈕的位置;經過傳入圖片獲取圖片在屏幕上的定位,一旦獲取到值則退出,不然繼續嘗試''' picture = './img/' + picture count = 5 while count > 0: point = pyautogui.locateCenterOnScreen(picture) if point is not None: return point else: count -= 1 def get_range(picture): '''用模糊匹配獲得某個按鈕的大概位置,通常是在那種點擊屏幕任意位置的狀況,或只須要知道某個按鈕在不在當前屏幕的狀況使用 要動的圖片採用模糊匹配,不然精確匹配的話,圖片一直在動像素也在變化,就不能定位到了''' picture = './img/' + picture count = 5 while count > 0: range = pyautogui.locateCenterOnScreen(picture, grayscale=True, confidence=0.5) if range is not None: return range else: count -= 1 def click_button(picture,accurate=True): '''點擊按鈕的函數,默認精確度爲True,即默認爲精確點擊,若是accurate=False,則爲模糊點擊,用於動態圖形按鈕''' if accurate==True: action = get_point(picture) else: action = get_range(picture) if action is not None: pyautogui.click(action,duration=0.5) return True #點擊成功則返回True else: return None #經過這個返回值斷定有沒有點擊成功 def on_fight(sec): '''這個函數用於模擬從【準備】到【戰鬥結束】這段時間,在這段時間裏程序應該是阻塞的,這樣就不用一直去找對應的按鈕,從而消耗大量的系統資源''' fight_run = click_button('zhunbei.PNG') #點擊準備按鈕則戰鬥開始 if fight_run is not None: #若是成功點擊了準備按鈕則表明戰鬥開始,程序進入尋找【戰鬥結束按鈕】的狀態 count = 0 while True: time.sleep(sec) #設定每幾秒檢測一次戰鬥是否結束,這個值能夠具體狀況設置 fight_over = click_button('over.PNG') if fight_over is not None: return True else: count +=1 #記錄循環次數 if count*sec > 600: '''用循環次數乘以中斷時間,大約等於戰鬥過程的時間,這裏的意思是戰鬥過程大於10分鐘,通常這種狀況,確定 是在點擊了準備以後,戰鬥過程當中異常中斷,這時候程序會一直陷入這個尋找戰鬥結束的死循環中,但這是沒有意義的, 因此直接退出整個程序''' exit(1) else: return None #若是沒有點擊【準備】按鈕,則返回爲空,繼續進入下一次尋找進入戰鬥起始按鈕的過程 def cycle_fight(sec): '''用戶循環重複的戰鬥場景,若是刷覺醒材料,刷御魂''' while True: click_button('tiaozhan.PNG') on_fight(sec) def story_task(): '''用於過廢話連篇的劇情''' while True: click_button('tiaoguo.PNG') click_button('dialogue.PNG') click_button('storyJump.PNG') def explore_task(sec): '''用於過探索副本''' while True: click_button('fight.PNG',accurate=False) click_button('masterFight.PNG',accurate=False) on_fight(sec) #explore_task() # cycle_fight(10) story_task()
這樣一來雖然下降了系統資源消耗但代碼邏輯變得極爲複雜,而後便想到用多線程封裝,以後效率確實極大的提高了:
import pyautogui,time import threading pyautogui.FAILSAFE = True '''PyAutoGUI提供了一個保護措施。當pyautogui.FAILSAFE = True時,若是把鼠標光標在屏幕左上角, PyAutoGUI函數就會產生pyautogui.FailSafeException異常,用於在程序失控時退出''' time.sleep(2) class FindButton(threading.Thread): def __init__(self, picture): super(FindButton, self).__init__() self.picture = './img/' + picture def run(self): while True: self.point = pyautogui.locateCenterOnScreen(self.picture, confidence=0.8) if self.point is not None: pyautogui.click(self.point, duration=0.5) challenge = FindButton('tiaozhan.PNG') prepare = FindButton('zhunbei.PNG') over = FindButton('over.PNG') challenge.start() prepare.start() over.start()
可是這樣一來,系統資源的消耗也成倍的增長了,至關於每多一個點擊操做,就要多使用一倍的系統資源。那不如用協程來解決吧,既是單線程,又能夠異步進行;
最後證實協程比多線程稍慢(畢竟協程是須要排隊的,協程直接的切換也是須要消耗時間的),比單線程則是快了太多了
並且消耗的系統資源也極大的下降了(甚至比單線程的狀況還低),而且代碼也簡單了太多了!異步
import gevent import pyautogui def click(picture): picture = './img/' + picture while True: point = pyautogui.locateCenterOnScreen(picture, confidence=0.8) if point is None: gevent.sleep(1) else: pyautogui.click(point, duration=0.5) def cycle_fight(): '''用於循環重複的戰鬥場景,若是刷覺醒材料,刷御魂''' gevent.joinall([ #利用joinall方法將每一步操做加入協程池中 gevent.spawn(click,'tiaozhan.PNG'), #每個協程的加入方法是:(函數名,參數) gevent.spawn(click,'zhunbei.PNG'), gevent.spawn(click,'over.PNG') ]) def story_task(): ''''用於過廢話連篇的劇情任務''' gevent.joinall([ gevent.spawn(click, 'dialogue.PNG'), gevent.spawn(click, 'tiaoguo.PNG'), gevent.spawn(click, 'storyJump.PNG'), gevent.spawn(click, 'fight.PNG'), gevent.spawn(click, 'zhunbei.PNG'), gevent.spawn(click, 'over.PNG') ]) def explore_task(): '''用於過探索副本''' gevent.joinall([ gevent.spawn(click, 'fight.PNG'), gevent.spawn(click, 'masterFight.PNG'), gevent.spawn(click, 'zhunbei.PNG'), gevent.spawn(click, 'over.PNG') ]) cycle_fight()