答題遊戲現在很火,但是,價值卻不如以前了。爲什麼這麼晚纔想着去寫這種助手呢!煩躁
這次改進主要是讓效果更好,操作更爲簡單(這是最大的改進),現在只需要運行,按回車,就可以了,不再需要外部軟件輔助。不過,這裏卻損失了一點效率,畢竟答題時間就10秒,效率也是很重要的。所以呀,實際上效果不是很好,現在多數娛樂效果吧,有興趣的小夥伴可以拿去玩玩。
本次程序用到的工具:python3.6,adb驅動,我已經打包成exe了,所以,只是想玩玩的就不必在意這些了,下載鏈接:鏈接:https://pan.baidu.com/s/1ggMaOqn 密碼:f8eo(csdn上傳不了zip文件,莫名其妙)
本次代碼相比上次主體部分改動不大,註釋我也沒做更新,但應該也看得懂的,直接上代碼了:
# _*_ coding:UTF-8 _*_
import numpy as np
import win32con
import ctypes
import ctypes.wintypes
import threading
import time
import os
import subprocess
from PIL import Image
from aip import AipOcr#百度的api,百度官網有教程
import shutil
import string
import urllib
#熱鍵功能,獨立的一個線程
class Hotkey(threading.Thread): #創建一個Thread.threading的擴展類
def run(self):
global EXIT #定義全局變量,這個可以在不同線程間共用
global RUN #定義全局變量,這個可以在不同線程間共用
user32 = ctypes.windll.user32 #加載user32.dll
try:
if not user32.RegisterHotKey(None, ID1, 0, HOTKEY_RUN): # 註冊快捷鍵F10並判斷是否成功,該熱鍵用於結束程序,且最好這麼結束,否則影響下一次註冊熱鍵。
print ("Unable to register id"), ID1 # 返回一個錯誤信息
if not user32.RegisterHotKey(None, ID2, 0, HOTKEY_EXIT): # 註冊快捷鍵F10並判斷是否成功,該熱鍵用於結束程序,且最好這麼結束,否則影響下一次註冊熱鍵。
print ("Unable to register id"), ID2 # 返回一個錯誤信息
#以下爲檢測熱鍵是否被按下,並在最後釋放快捷鍵
msg = ctypes.wintypes.MSG()
while True:
if user32.GetMessageA(ctypes.byref(msg), None, 0, 0) != 0:
if msg.message == win32con.WM_HOTKEY:
if msg.wParam == ID2:
EXIT=True
return
elif msg.wParam == ID1:
RUN=True
user32.TranslateMessage(ctypes.byref(msg))
user32.DispatchMessageA(ctypes.byref(msg))
finally:
user32.UnregisterHotKey(None, ID1)#必須得釋放熱鍵,否則下次就會註冊失敗,所以當程序異常退出,沒有釋放熱鍵,
#那麼下次很可能就沒辦法註冊成功了,這時可以換一個熱鍵測試
user32.UnregisterHotKey(None, ID2)
class Ans():
def main(self):
#im_name=os.listdir(filePath)#獲取圖片名
self.cut()#對圖片進行裁剪
f=open('im.jpg','rb')#二進制方式打開圖文件
image=f.read()#這裏好像必須命名爲image,百度的api限定,有點不能理解,有待考察
#im=base64.b64encode(f.read()) #讀取文件內容,轉換爲base64編碼
#這裏是每個百度雲賬號獨立的一些ID
APP_ID='10687373'
API_KEY='BIziiO4FQbN7n7iu5kPCuEMF'
SECRET_KEY='yOxbhG3qZp0KvNkB42hstT4aNWXHOitZ'
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)#這個就是百度的api,可以獲取一個相當於實例對象的東西,可以調用函數
information=client.basicGeneral(image)#ocr函數,打印出來是json格式的
#這裏是普通版的
STR=''#存儲識別出來的文字
num=information['words_result_num']
for i in range(0,num):#根據格式得出來的循環,答案放在前面,題目放在後面,保證題目能完成搜索到
if i>=0 and i<3:
STR+=information['words_result'][num-i-1]['words']
STR+=' '
else:
STR+=information['words_result'][i-3]['words']
#下面幾行是對得到的字符串做一些處理,去掉一些符號,因爲百度搜索限制38個字以內,個人覺得這裏寫的很醜,無奈沒找到好的方法
#STR=STR[1:len(STR)]
STR=STR.translate(string.punctuation)
DEL=['以下','哪個','是','的','什麼','下列','哪種']#這鞋子替換成空格,好處在於百度效果很好吧,親測結果
for x in DEL:
STR = STR.replace(x,' ')
self.find(STR)#調用百度搜索,並保存到本地,再用默認瀏覽器打開
print (STR)
f.close()#關閉文件,不然後面刪除不掉
#shutil.rmtree(path)#刪除之前獲得的圖片文件以及這個文件夾,以便下次判斷是否已經截屏
#打開圖片並裁剪
def cut(self):
#im_name=os.listdir(filePath)#獲取圖片名,因爲截屏靠的外部軟件,沒辦法修改截屏圖片的名字
im=Image.open(filePath+'\\'+"screenshot.jpg")
if len(im.split()) == 4:
r, g, b, a = im.split()#圖片有四通道
im=Image.merge("RGB",(r,g,b))
#下面這篇代碼也寫的不夠優雅,可是沒找到好的辦法
box=(80,330,1000,1300)
crop_im=im.crop(box)#裁剪函數
array_im=np.array(crop_im.convert('L'))
im.close()
x=970#記錄最下邊界
for i in range(300):
if array_im[969-i][0]==255:
x=969-i-50
break
crop_im2=crop_im.crop((0,0,919,x))
crop_im2.save('im.jpg')#保存本地,有不保存就直接用二進制打開的方式嗎??求教
#調用百度搜索,並保存到本地,再用默認瀏覽器打開,參考百度的資料,具體哪篇忘記了,,如有問題請聯繫我。。
def find(self,STR):
url = "http://www.baidu.com/s"
search = [('w',STR)]
getString = url + "?" + urllib.parse.urlencode(search)
req = urllib.request.Request(getString)
fd = urllib.request.urlopen(req)
baiduResponse=fd.read()
fobj=open("baidu.html",'wb+')
fobj.write(baiduResponse)
os.startfile('baidu.html')#這個函數就很剛好的解決了大問題,可以用瀏覽器打開網頁,不然就得手點了
fobj.close()
def getPicture(self,filePath,ADBpath):
#ADBpath=filePath+'\\adb\\adb '
subprocess.call(ADBpath+"shell /system/bin/screencap -p /sdcard/screenshot.jpg",stdout=subprocess.PIPE, shell=subprocess.PIPE)
subprocess.call(ADBpath+"pull /sdcard/screenshot.jpg "+filePath+"/screenshot.jpg",stdout=subprocess.PIPE, shell=subprocess.PIPE)
if __name__ == '__main__':
HOTKEY_RUN=0x0D
HOTKEY_EXIT=win32con.VK_F8#結束程序的快捷鍵F6,自行根據需要修改,一定要手動關閉程序,否則下次這個快捷鍵就用不了了(python3.6沒這個問題?)
EXIT = False #用來傳遞退出的參數
RUN = False
ID1=106 #註冊熱鍵的唯一id,用來區分熱鍵
ID2=105
filePath=os.path.split(os.path.realpath(__file__))[0]
ADBpath=filePath+'\\adb\\adb '
ans=Ans()#創建實例
hotkey = Hotkey()
hotkey.start()#啓動線程
print ("等待手機設備連接USB...如無設備需要連接請按F8結束程序")
subprocess.call(ADBpath+" wait-for-device",stdout=subprocess.PIPE, shell=subprocess.PIPE)
print ("截屏快捷鍵:回車,關閉程序快捷鍵:F8")
while(True):
if RUN==True:
print ("開始識別")
start=time.time()
ans.getPicture(filePath,ADBpath)
ans.main()
subprocess.call(ADBpath+' shell rm /sdcard/screenshot.jpg',stdout=subprocess.PIPE, shell=subprocess.PIPE)
end=time.time()
print ("一次識別結束,用時:",end-start)
print ()
RUN=False
elif EXIT==True: #退出程序
break
效率還是這個程序最大的問題,但是,目前沒想到解決辦法,就先這樣吧,不過,還是有那麼一點幫助的。