答题游戏现在很火,但是,价值却不如以前了。为什么这么晚才想着去写这种助手呢!烦躁
这次改进主要是让效果更好,操作更为简单(这是最大的改进),现在只需要运行,按回车,就可以了,不再需要外部软件辅助。不过,这里却损失了一点效率,毕竟答题时间就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
效率还是这个程序最大的问题,但是,目前没想到解决办法,就先这样吧,不过,还是有那么一点帮助的。