From 05c32f2cf746077ecdf2c76869f8fd66cff4e2d0 Mon Sep 17 00:00:00 2001 From: "joe.wu" Date: Mon, 29 Jan 2018 01:03:11 +0800 Subject: [PATCH 1/6] support for mutiple adb devices --- GetQuestionAndroid.py | 17 +++++++++-------- common/ocr.py | 4 +++- common/screenshot.py | 29 +++++++++++++++++++++++++---- config/configure.conf | 20 ++++++++++++++------ 4 files changed, 51 insertions(+), 19 deletions(-) diff --git a/GetQuestionAndroid.py b/GetQuestionAndroid.py index 1d7768c..b7564cf 100644 --- a/GetQuestionAndroid.py +++ b/GetQuestionAndroid.py @@ -33,8 +33,8 @@ #ocr_img_baidu: 题目和选项一起截,使用 baidu ocr,需配置 key # question, choices = ocr.ocr_img(img, config) - question, choices = ocr.ocr_img_tess(img, config) - # question, choices = ocr.ocr_img_baidu(img, config) + # question, choices = ocr.ocr_img_tess(img, config) + question, choices = ocr.ocr_img_baidu(img, config) #end_time2 = time.clock() #print(end_time2 - end_time) @@ -49,12 +49,13 @@ # methods.run_algorithm(2, question, choices) # 多线程 - m1 = Thread(methods.run_algorithm(0, question, choices)) - m2 = Thread(methods.run_algorithm(1, question, choices)) - m3 = Thread(methods.run_algorithm(2, question, choices)) - m1.start() - m2.start() - m3.start() + if question and choices: + m1 = Thread(methods.run_algorithm(0, question, choices)) + m2 = Thread(methods.run_algorithm(1, question, choices)) + m3 = Thread(methods.run_algorithm(2, question, choices)) + m1.start() + m2.start() + m3.start() end_time3 = time.clock() print('用时: {0}'.format(end_time3 - t)) diff --git a/common/ocr.py b/common/ocr.py index afc4878..7575aee 100644 --- a/common/ocr.py +++ b/common/ocr.py @@ -173,6 +173,7 @@ def ocr_img_baidu(image, config): combine_region = config.get("region", "combine_region").replace(' ','').split(',') combine_region = list(map(int, combine_region)) region_im = image.crop((combine_region[0], combine_region[1], combine_region[2], combine_region[3])) + # region_im.show() # 转化为灰度图 #region_im = region_im.convert('L') @@ -195,7 +196,8 @@ def ocr_img_baidu(image, config): choices = [x.replace(' ', '') for x in choices] else: print(Fore.RED + '截图区域设置错误,请重新设置' + Fore.RESET) - exit(0) + return ('','') + # exit(0) # 处理出现问题为两行或三行 if choices[0].endswith('?'): diff --git a/common/screenshot.py b/common/screenshot.py index 66a69c0..af5b6e8 100644 --- a/common/screenshot.py +++ b/common/screenshot.py @@ -6,6 +6,11 @@ import os import sys from PIL import Image +import configparser + +# 读取配置文件 +config = configparser.ConfigParser() +config.read('./config/configure.conf', encoding='utf-8') # SCREENSHOT_WAY 是截图方法,经过 check_screenshot 后,会自动递减,不需手动修改 @@ -18,24 +23,40 @@ def pull_screenshot(): 可根据效率及适用性由高到低排序 """ global SCREENSHOT_WAY + + # 兼容多个adb设备的情况 + device_cmd = '' + try: + devices = os.popen('adb devices').readlines()[1:-1] + devices_count = len(devices) + if devices_count > 1: + adb_device = config.get('device', 'adb_device') + device_cmd = ' -s ' + adb_device + elif devices_count == 0: + print('当前暂无已连接的adb设备') + exit(0) + except Exception: + pass + if 1 <= SCREENSHOT_WAY <= 3: process = subprocess.Popen( - 'adb shell screencap -p', + 'adb' + device_cmd + ' shell screencap -p', shell=True, stdout=subprocess.PIPE) binary_screenshot = process.stdout.read() if SCREENSHOT_WAY == 2: binary_screenshot = binary_screenshot.replace(b'\r\n', b'\n') # binary_screenshot = binary_screenshot.split(b' ') # binary_screenshot = binary_screenshot[len(binary_screenshot) - 1] - #print(binary_screenshot) + # print(binary_screenshot) elif SCREENSHOT_WAY == 1: binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n') f = open('screenshot.png', 'wb') f.write(binary_screenshot) f.close() elif SCREENSHOT_WAY == 0: - os.system('adb shell screencap -p /sdcard/screenshot.png') - os.system('adb pull /sdcard/screenshot.png .') + os.system('adb' + device_cmd + + ' shell screencap -p /sdcard/screenshot.png') + os.system('adb' + device_cmd + ' pull /sdcard/screenshot.png .') def check_screenshot(): diff --git a/config/configure.conf b/config/configure.conf index 79c85a1..6bff065 100644 --- a/config/configure.conf +++ b/config/configure.conf @@ -4,19 +4,27 @@ question_region = 50, 350, 1000, 560 choices_region = 75, 535, 1000, 1200 # 题目和选项一起的区域 -combine_region = 50, 350, 1000, 1200 +# 波波视频百万超人 +combine_region = 50, 180, 700, 900 + +# 贴吧百万富翁 +# combine_region = 50, 200, 700, 900 [baidu_api] -APP_ID = -API_KEY = -SECRET_KEY = +APP_ID = 10759939 +API_KEY = 1GCpUfblPFChsr6dVs2c7yzF +SECRET_KEY = zZS3GxQN9WBc9KlyW0MplCgnqcqjBQCs [tesseract] # windows # tesseract 安装路径 -tesseract_cmd = C:\\Program Files (x86)\\Tesseract-OCR\\tesseract +tesseract_cmd = G:\\Tesseract-OCR\\tesseract # 语言包目录和参数 -tessdata_dir_config = --tessdata-dir "C:\\Program Files (x86)\\Tesseract-OCR\\tessdata" --psm 6 +tessdata_dir_config = --tessdata-dir "G:\\Tesseract-OCR\\tessdata" --psm 6 # mac 环境, 文件夹分割请使用 / 代替 \\ 如 '/usr/local/Cellar/tesseract/3.05.01/bin/tesseract' + +[device] +# adb 设备名字,适用于有多个adb设备时,只有一个不用配置 +adb_device = 127.0.0.1:62027 \ No newline at end of file From ab029eb2979ca17bab402970d353f0b1e6278e95 Mon Sep 17 00:00:00 2001 From: travellerwjoe Date: Tue, 30 Jan 2018 18:11:36 +0800 Subject: [PATCH 2/6] optimize speed of runtime by using binary of image --- GetQuestionAndroid.old.py | 67 ++++++++++++++++++++++++++++++ GetQuestionAndroid.py | 54 +++++++++++++------------ common/screenshot.old.py | 85 +++++++++++++++++++++++++++++++++++++++ common/screenshot.py | 25 +++++++----- 4 files changed, 196 insertions(+), 35 deletions(-) create mode 100644 GetQuestionAndroid.old.py create mode 100644 common/screenshot.old.py diff --git a/GetQuestionAndroid.old.py b/GetQuestionAndroid.old.py new file mode 100644 index 0000000..11dde7b --- /dev/null +++ b/GetQuestionAndroid.old.py @@ -0,0 +1,67 @@ +# -*- coding: utf-8 -*- + +# @Author : Skye +# @Time : 2018/1/8 20:38 +# @desc : 答题闯关辅助,截屏 ,OCR 识别,百度搜索 + + +from PIL import Image +from common import screenshot, ocr, methods +from threading import Thread +import time +import configparser + +# 读取配置文件 +config = configparser.ConfigParser() +config.read('./config/configure.conf', encoding='utf-8') + + +while True: + # 截图 + t = time.clock() + # screenshot.check_screenshot() + + #end_time = time.clock() + #print(end_time - t) + + img = Image.open("./screenshot.png") + + # 文字识别,可选 Tesseract 和 Baidu ,请在 config/configure.conf 中进行相应配置 + + #ocr_img: 需要分别截取题目和选项区域,使用 Tesseract + #ocr_img_tess: 题目和选项一起截,使用 Tesseract + #ocr_img_baidu: 题目和选项一起截,使用 baidu ocr,需配置 key + + # question, choices = ocr.ocr_img(img, config) + # question, choices = ocr.ocr_img_tess(img, config) + question, choices = ocr.ocr_img_baidu(img, config) + + #end_time2 = time.clock() + #print(end_time2 - end_time) + + # 用不同方法输出结果,取消某个方法在前面加上# + + # # 打开浏览器方法搜索问题 + # methods.run_algorithm(0, question, choices) + # # 将问题与选项一起搜索方法,并获取搜索到的结果数目 + # methods.run_algorithm(1, question, choices) + # # 用选项在问题页面中计数出现词频方法 + # methods.run_algorithm(2, question, choices) + + # 多线程 + if question and choices: + m1 = Thread(methods.run_algorithm(0, question, choices)) + m2 = Thread(methods.run_algorithm(1, question, choices)) + m3 = Thread(methods.run_algorithm(2, question, choices)) + m1.start() + m2.start() + m3.start() + + end_time3 = time.clock() + print('用时: {0}'.format(end_time3 - t)) + + go = input('输入回车继续运行,输入 n 回车结束运行: ') + if go == 'n': + break + + print('------------------------') diff --git a/GetQuestionAndroid.py b/GetQuestionAndroid.py index b7564cf..16e3430 100644 --- a/GetQuestionAndroid.py +++ b/GetQuestionAndroid.py @@ -3,11 +3,11 @@ # @Author : Skye # @Time : 2018/1/8 20:38 # @desc : 答题闯关辅助,截屏 ,OCR 识别,百度搜索 - - +import io from PIL import Image from common import screenshot, ocr, methods from threading import Thread +import traceback import time import configparser @@ -15,30 +15,25 @@ config = configparser.ConfigParser() config.read('./config/configure.conf', encoding='utf-8') - while True: - # 截图 - t = time.clock() - screenshot.check_screenshot() - - #end_time = time.clock() - #print(end_time - t) - img = Image.open("./screenshot.png") - - # 文字识别,可选 Tesseract 和 Baidu ,请在 config/configure.conf 中进行相应配置 - - #ocr_img: 需要分别截取题目和选项区域,使用 Tesseract - #ocr_img_tess: 题目和选项一起截,使用 Tesseract - #ocr_img_baidu: 题目和选项一起截,使用 baidu ocr,需配置 key - # question, choices = ocr.ocr_img(img, config) - # question, choices = ocr.ocr_img_tess(img, config) - question, choices = ocr.ocr_img_baidu(img, config) - - #end_time2 = time.clock() - #print(end_time2 - end_time) - + t = time.clock() + # 截图 + bScreenshot = screenshot.check_screenshot() + # bScreenshot.save(io.BytesIO(),'PNG') + # bScreenshot.seek(0) + # bScreenImg = bScreenshot.read() + try: + image_file = io.BytesIO(bScreenshot) + img = Image.open(image_file) + # 文字识别 + question, choices = ocr.ocr_img_baidu(img, config) + except Exception: + print('识别失败', traceback.format_exc()) + continue + + # t = time.clock() # 用不同方法输出结果,取消某个方法在前面加上# # # 打开浏览器方法搜索问题 @@ -49,6 +44,13 @@ # methods.run_algorithm(2, question, choices) # 多线程 + # if question and choices: + # m1 = Thread(target=methods.run_algorithm, args=(0, question, choices)) + # m2 = Thread(target=methods.run_algorithm, args=(1, question, choices)) + # m3 = Thread(target=methods.run_algorithm, args=(2, question, choices)) + # m1.start() + # m2.start() + # m3.start() if question and choices: m1 = Thread(methods.run_algorithm(0, question, choices)) m2 = Thread(methods.run_algorithm(1, question, choices)) @@ -57,11 +59,11 @@ m2.start() m3.start() - end_time3 = time.clock() - print('用时: {0}'.format(end_time3 - t)) + end_time = time.clock() + print('用时: {0}'.format(end_time - t)) go = input('输入回车继续运行,输入 n 回车结束运行: ') if go == 'n': break - print('------------------------') + print('------------------------') \ No newline at end of file diff --git a/common/screenshot.old.py b/common/screenshot.old.py new file mode 100644 index 0000000..af5b6e8 --- /dev/null +++ b/common/screenshot.old.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +""" +手机屏幕截图的代码 ,用管道或取图片数据比直接传输图片快,来自 https://github.com/wangshub/wechat_jump_game +""" +import subprocess +import os +import sys +from PIL import Image +import configparser + +# 读取配置文件 +config = configparser.ConfigParser() +config.read('./config/configure.conf', encoding='utf-8') + + +# SCREENSHOT_WAY 是截图方法,经过 check_screenshot 后,会自动递减,不需手动修改 +SCREENSHOT_WAY = 3 + + +def pull_screenshot(): + """ + 获取屏幕截图,目前有 0 1 2 3 四种方法,未来添加新的平台监测方法时, + 可根据效率及适用性由高到低排序 + """ + global SCREENSHOT_WAY + + # 兼容多个adb设备的情况 + device_cmd = '' + try: + devices = os.popen('adb devices').readlines()[1:-1] + devices_count = len(devices) + if devices_count > 1: + adb_device = config.get('device', 'adb_device') + device_cmd = ' -s ' + adb_device + elif devices_count == 0: + print('当前暂无已连接的adb设备') + exit(0) + except Exception: + pass + + if 1 <= SCREENSHOT_WAY <= 3: + process = subprocess.Popen( + 'adb' + device_cmd + ' shell screencap -p', + shell=True, stdout=subprocess.PIPE) + binary_screenshot = process.stdout.read() + if SCREENSHOT_WAY == 2: + binary_screenshot = binary_screenshot.replace(b'\r\n', b'\n') + # binary_screenshot = binary_screenshot.split(b' ') + # binary_screenshot = binary_screenshot[len(binary_screenshot) - 1] + # print(binary_screenshot) + elif SCREENSHOT_WAY == 1: + binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n') + f = open('screenshot.png', 'wb') + f.write(binary_screenshot) + f.close() + elif SCREENSHOT_WAY == 0: + os.system('adb' + device_cmd + + ' shell screencap -p /sdcard/screenshot.png') + os.system('adb' + device_cmd + ' pull /sdcard/screenshot.png .') + + +def check_screenshot(): + """ + 检查获取截图的方式 + """ + global SCREENSHOT_WAY + if os.path.isfile('screenshot.png'): + try: + os.remove('screenshot.png') + except Exception: + pass + if SCREENSHOT_WAY < 0: + print('暂不支持当前设备') + sys.exit() + pull_screenshot() + try: + Image.open('./screenshot.png').load() + print('采用方式 {} 获取截图'.format(SCREENSHOT_WAY)) + except Exception: + SCREENSHOT_WAY -= 1 + check_screenshot() + +if __name__ == '__main__': + check_screenshot() + img = Image.open("./screenshot.png") \ No newline at end of file diff --git a/common/screenshot.py b/common/screenshot.py index af5b6e8..caf969a 100644 --- a/common/screenshot.py +++ b/common/screenshot.py @@ -43,6 +43,7 @@ def pull_screenshot(): 'adb' + device_cmd + ' shell screencap -p', shell=True, stdout=subprocess.PIPE) binary_screenshot = process.stdout.read() + binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n') if SCREENSHOT_WAY == 2: binary_screenshot = binary_screenshot.replace(b'\r\n', b'\n') # binary_screenshot = binary_screenshot.split(b' ') @@ -50,13 +51,18 @@ def pull_screenshot(): # print(binary_screenshot) elif SCREENSHOT_WAY == 1: binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n') - f = open('screenshot.png', 'wb') - f.write(binary_screenshot) - f.close() + return binary_screenshot + # f = open('screenshot.png', 'wb') + # f.write(binary_screenshot) + # f.close() elif SCREENSHOT_WAY == 0: - os.system('adb' + device_cmd + - ' shell screencap -p /sdcard/screenshot.png') + os.system('adb' + device_cmd + ' shell screencap -p /sdcard/screenshot.png') os.system('adb' + device_cmd + ' pull /sdcard/screenshot.png .') + file = open('./screenshot.png', 'b') + try: + return file.read() + finally: + file.close() def check_screenshot(): @@ -72,14 +78,15 @@ def check_screenshot(): if SCREENSHOT_WAY < 0: print('暂不支持当前设备') sys.exit() - pull_screenshot() - try: - Image.open('./screenshot.png').load() + screenshot = pull_screenshot() + if screenshot is not None: print('采用方式 {} 获取截图'.format(SCREENSHOT_WAY)) - except Exception: + return screenshot + else: SCREENSHOT_WAY -= 1 check_screenshot() + if __name__ == '__main__': check_screenshot() img = Image.open("./screenshot.png") \ No newline at end of file From e4ff0cdc48761c9d5943aada2ede80058ba991cb Mon Sep 17 00:00:00 2001 From: travellerwjoe Date: Tue, 30 Jan 2018 18:13:25 +0800 Subject: [PATCH 3/6] optimize search of the mutilple line question --- common/ocr.py | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/common/ocr.py b/common/ocr.py index 7575aee..8c06156 100644 --- a/common/ocr.py +++ b/common/ocr.py @@ -173,26 +173,23 @@ def ocr_img_baidu(image, config): combine_region = config.get("region", "combine_region").replace(' ','').split(',') combine_region = list(map(int, combine_region)) region_im = image.crop((combine_region[0], combine_region[1], combine_region[2], combine_region[3])) - # region_im.show() # 转化为灰度图 #region_im = region_im.convert('L') # 把图片变成二值图像 - #region_im = binarizing(region_im, 190) - #region_im.show() + # region_im = binarizing(region_im, 190) + # region_im.show() img_byte_arr = io.BytesIO() region_im.save(img_byte_arr, format='PNG') image_data = img_byte_arr.getvalue() # base64_data = base64.b64encode(image_data) response = client.basicGeneral(image_data) - #print(response) words_result = response['words_result'] - + texts = [x['words'] for x in words_result] - # print(texts) if len(texts) > 2: - question = texts[0] - choices = texts[1:] + question = ''.join(texts[0:-3]) + choices = texts[-3:] choices = [x.replace(' ', '') for x in choices] else: print(Fore.RED + '截图区域设置错误,请重新设置' + Fore.RESET) @@ -200,14 +197,14 @@ def ocr_img_baidu(image, config): # exit(0) # 处理出现问题为两行或三行 - if choices[0].endswith('?'): - question += choices[0] - choices.pop(0) - elif choices[1].endswith('?'): - question += choices[0] - question += choices[1] - choices.pop(0) - choices.pop(0) + # if choices[0].endswith('?'): + # question += choices[0] + # choices.pop(0) + # elif choices[1].endswith('?'): + # question += choices[0] + # question += choices[1] + # choices.pop(0) + # choices.pop(0) return question, choices From a00891e39a8e9450d2759412026acccd2bb74c0a Mon Sep 17 00:00:00 2001 From: travellerwjoe Date: Wed, 31 Jan 2018 18:14:05 +0800 Subject: [PATCH 4/6] add config of chongdingdahui --- config/configure.conf | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/config/configure.conf b/config/configure.conf index 6bff065..f76eb1e 100644 --- a/config/configure.conf +++ b/config/configure.conf @@ -5,15 +5,18 @@ choices_region = 75, 535, 1000, 1200 # 题目和选项一起的区域 # 波波视频百万超人 -combine_region = 50, 180, 700, 900 +combine_region = 50, 180, 700, 650 # 贴吧百万富翁 # combine_region = 50, 200, 700, 900 +#冲顶大会 +# combine_region = 0, 180, 700, 580 + [baidu_api] -APP_ID = 10759939 -API_KEY = 1GCpUfblPFChsr6dVs2c7yzF -SECRET_KEY = zZS3GxQN9WBc9KlyW0MplCgnqcqjBQCs +APP_ID = +API_KEY = +SECRET_KEY = [tesseract] # windows From 9b69dd51681312c3070e2103373329888ced82d1 Mon Sep 17 00:00:00 2001 From: travellerwjoe Date: Wed, 31 Jan 2018 18:17:01 +0800 Subject: [PATCH 5/6] method 3 now only search the left area of Baidu result page. --- common/methods.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/common/methods.py b/common/methods.py index 6db0cb4..124dd56 100644 --- a/common/methods.py +++ b/common/methods.py @@ -7,6 +7,7 @@ import requests import webbrowser import urllib.parse +from pyquery import PyQuery as pq # # 颜色兼容Win 10 from colorama import init,Fore @@ -39,7 +40,8 @@ def count_base(question,choices): # 请求 req = requests.get(url='http://www.baidu.com/s', params={'wd':question}) content = req.text - #print(content) + doc = pq(content) + content = doc.find('#content_left').html() counts = [] print('Question: '+question) if '不是' in question: From b8195f2736da7dc7798e819a54f635f74e9853d7 Mon Sep 17 00:00:00 2001 From: travellerwjoe Date: Thu, 1 Feb 2018 18:13:08 +0800 Subject: [PATCH 6/6] highlight options background & display it when there is a baike recommendation on the page --- common/methods.py | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/common/methods.py b/common/methods.py index 124dd56..7e127d5 100644 --- a/common/methods.py +++ b/common/methods.py @@ -1,4 +1,4 @@ -# -*- coding: utf-8 -*- +# -*- coding: utf-8 -*- # @Author : Skye # @Time : 2018/1/9 10:39 @@ -10,7 +10,7 @@ from pyquery import PyQuery as pq # # 颜色兼容Win 10 -from colorama import init,Fore +from colorama import init,Fore,Back init() def open_webbrowser(question): @@ -38,19 +38,31 @@ def open_webbrowser_count(question,choices): def count_base(question,choices): print('\n-- 方法3: 题目搜索结果包含选项词频计数法 --\n') # 请求 + question = '寒食节是为了纪念谁' + choices = ['屈原','介之推','鲁迅'] req = requests.get(url='http://www.baidu.com/s', params={'wd':question}) content = req.text doc = pq(content) content = doc.find('#content_left').html() + baike_content = doc.find('.op_exactqa_main').html() counts = [] + baike_recommend = '' print('Question: '+question) if '不是' in question: print('**请注意此题为否定题,选计数最少的**') for i in range(len(choices)): counts.append(content.count(choices[i])) + if baike_content and baike_content.count(choices[i]): + baike_recommend = choices[i] #print(choices[i] + " : " + str(counts[i])) output(choices, counts) + if baike_recommend: + print() + print(Fore.YELLOW + '{0}:{1}'.format('百科推荐', baike_recommend) + Fore.RESET) + print() + + def output(choices, counts): counts = list(map(int, counts)) #print(choices, counts) @@ -64,22 +76,24 @@ def output(choices, counts): if index_max == index_min: print(Fore.RED + "高低计数相等此方法失效!" + Fore.RESET) return - + print(Back.WHITE) for i in range(len(choices)): print() if i == index_max: # 绿色为计数最高的答案 - print(Fore.GREEN + "{0} : {1} ".format(choices[i], counts[i]) + Fore.RESET) + print(Fore.GREEN + "选项 {0} ---- {1} : {2} ".format(str(i + 1), choices[i], counts[i]) + Fore.RESET) elif i == index_min: # 红色为计数最低的答案 - print(Fore.MAGENTA + "{0} : {1}".format(choices[i], counts[i]) + Fore.RESET) + print(Fore.MAGENTA + "选项 {0} ---- {1} : {2}".format(str(i + 1), choices[i], counts[i]) + Fore.RESET) else: - print("{0} : {1}".format(choices[i], counts[i])) - + print(Fore.BLACK + "选项 {0} ---- {1} : {2}".format(str(i + 1), choices[i], counts[i]) + Fore.RESET) + + print(Back.RESET) def run_algorithm(al_num, question, choices): if al_num == 0: - open_webbrowser(question) + # open_webbrowser(question) + pass elif al_num == 1: open_webbrowser_count(question, choices) elif al_num == 2: