#AI系列#--AI应用之Python自动答题

user

雨橙

中国.四川.成都

世界之上、唯有远见、惟爱不变。


最近网上答题类应用特别火。加上看到网上的一个网友自动跳一跳游戏思路。于是乎就想自己实现一个自动答题的脚本。
下面我以微信小程序《头脑王者》为例说说这个自动答题的实现过程。

实现步骤如下:
第一步: 首先需要通过adb调试工具获取答题屏幕图片。然后识别图片。获取里面的文字。包括问题及答案。
第二步:通过获取在问题去百度搜索,然后找到出现频率最高在答案。
第三步:最后通过获取答案坐标匹配正确答案。模拟点击答题。

下面用代码解析实现步骤:

首先屏幕需要抓取。目前程序只支持安卓手机。暂时不支持苹果手机。
抓取屏幕我们需要开启手机调试模式。usb线连接pc。
用adb shell测试。如果没有安装adb。点击这里下载adb。下载后加环境变量就可以了。
然后我们可以通过测试adb shell screencap -p 来获取当前屏幕图像
#屏幕抓取
proobj = subprocess.Popen("adb shell screencap -p",shell=True,stdout=subprocess.PIPE)
screenobj = proobj.stdout.read()
screenobj = screenobj.replace(b"\r\r\n", b"\n")
with open("screen.jpg","wb") as f:
    f.write(screenobj)

我这里使用了IO写文件操作。可能会影响效率。建议使用BytesIO

屏幕抓取完成以后。我们需要通过PIL库来识别来处理图像。把我们需要的图像裁切出来。
问题和答案分别裁切。
#PIL裁剪图片
img = Image.open("screen.jpg")

title_box = (92,437,625,540)
title_img = img.crop(title_box)

answer_box = (148,530,602,1050)
answer_img = img.crop(answer_box)

title_img.save("__title.jpg")
answer_img.save("__answer.jpg")

坐标需要自己去训练出来。找出最合适的坐标位置。
这里还是用了IO操作。分别把问题和答案两个图片保存下来。方便后面我们分析。

接下来我们开始分析问题和答案图片里面的文字信息。把这些信息提取出来。
这里我们可以借助第三方库。也可以用百度AI开发平台。我这里使用百度ai里面的文字识别库
百度ai库的安装这里就不做详细说明了。点击看这里可以了解

#读取文件
def get_img_content(img_filepath):
    with open(img_filepath,"rb") as f:
        return f.read()


#获取问题及答案
def getTitleinfo(img):
    APP_ID = '12564346'
    API_KEY = 'M73As2xdfsdfCD74rH'
    SECRET_KEY = 'G4DlQ4LybuLN6EE5evgNt1'

    #文字识别
    client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
    res = client.basicGeneral(img)

    str = ""
    for line in res:
        if type(res[line]) == list:
            words = res[line]
            for x in words:
                str = str+x["words"]+","
    return str[:-1]


title_str = getTitleinfo(get_img_content("__title.jpg"))
answer_str = getTitleinfo(get_img_content("__answer.jpg"))
answer_str = answer_str.split(',')
result = []
for x in answer_str:
    result.append(x)

上面代码基于百度ai实现。最终我们把获取的答案放到一个列表中保存起来。后面会用到。


问题及答案文字信息获取以后。接下来我们开始去百度搜寻答案。实现过程如下:
# 远程获取答案
url = "http://www.baidu.com/s"
data = {
    "wd": title_str
}
headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"};
response = requests.get(url=url, params=data, headers=headers)
response.encoding = "utf-8"
html = response.text

reload(sys)
sys.setdefaultencoding('utf8')
for i in range(len(result)):
    result[i] = (html.count(result[i]),result[i],i)

result.sort(reverse=True)
print(data["wd"])
print("=============================================")
for x in result:
    print(str(x[0])+" | "+x[1]+" | "+str(x[2]))
print("=============================================")

这里需要使用requests模块,通过构造URL参数及请求头。来远程获取答案在搜索中出现的次数。次数最多的则为答案。最后将答案从新生产一个新的元组平排序。
(这个其实还是有误差的,有时候百度也搜索不到,所以这个方法仅供参考。)

到这里整个过程基本就完成了。最后一步就是模拟点击。
config = {
    "tounaowangzhe":{
        "title":(92,437,625,540),
        "answer":(148,530,602,1050),
        "point":[
            (357,595,471,627),
            (357,721,471,740),
            (357,847,471,853),
            (357,973,471,966)
        ]
    }
}

#模拟点击
def click(point):
    cmd = 'adb shell input swipe %s %s %s %s %s' % (
        point[0],
        point[1],
        point[0]+random.randint(0,3),
        point[1]+random.randint(0,3),
        200
    )
    os.system(cmd)

#开始点击答题
click(config["tounaowangzhe"]["point"][int(result[0][2])])

找到正确答案后。我们需要将答案坐标分析出来。保存下来。然后调用系统adb shell input swipe命令来模拟点击答题。
整个过程就完成了。


下面我贴上完整代码:
#!/usr/bin/pythyon
# _*_ coding:utf-8 _*_
# author: Robinn

import os
import sys
import PIL
import random
import requests
import subprocess

from io import BytesIO
from PIL import Image
from aip import AipImageClassify
from aip import AipOcr

while True:
    reload(sys)
    sys.setdefaultencoding('utf8')

    config = {
        "tounaowangzhe":{
            "title":(92,437,625,540),
            "answer":(148,530,602,1050),
            "point":[
                (357,595,471,627),
                (357,721,471,740),
                (357,847,471,853),
                (357,973,471,966)
            ]
        }
    }

    #模拟点击
    def click(point):
        cmd = 'adb shell input swipe %s %s %s %s %s' % (
            point[0],
            point[1],
            point[0]+random.randint(0,3),
            point[1]+random.randint(0,3),
            200
        )
        os.system(cmd)

    a = raw_input(u"请按下回车回答问题:")

    #屏幕抓取
    proobj = subprocess.Popen("adb shell screencap -p",shell=True,stdout=subprocess.PIPE)
    screenobj = proobj.stdout.read()
    screenobj = screenobj.replace(b"\r\r\n", b"\n")
    with open("screen.jpg","wb") as f:
        f.write(screenobj)
        

    #PIL裁剪图片
    img = Image.open("screen.jpg")

    title_box = (92,437,625,540)
    title_img = img.crop(title_box)

    answer_box = (148,530,602,1050)
    answer_img = img.crop(answer_box)

    title_img.save("__title.jpg")
    answer_img.save("__answer.jpg")

    #读取文件
    def get_img_content(img_filepath):
        with open(img_filepath,"rb") as f:
            return f.read()


    #获取问题及答案
    def getTitleinfo(img):
        APP_ID = '10704346'
        API_KEY = 'M73AwH6k1rpxdGEjFXCD74rH'
        SECRET_KEY = 'G4DlQ4GIW9vbcBQCLybuLN6EE5evgNt1'

        #文字识别
        client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
        res = client.basicGeneral(img)

        str = ""
        for line in res:
            if type(res[line]) == list:
                words = res[line]
                for x in words:
                    str = str+x["words"]+","
        return str[:-1]


    title_str = getTitleinfo(get_img_content("__title.jpg"))
    answer_str = getTitleinfo(get_img_content("__answer.jpg"))
    answer_str = answer_str.split(',')
    result = []
    for x in answer_str:
        result.append(x)



    # 远程获取答案
    url = "http://www.baidu.com/s"
    data = {
        "wd": title_str
    }
    headers = {"user-agent":"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36"};
    response = requests.get(url=url, params=data, headers=headers)
    response.encoding = "utf-8"
    html = response.text

    reload(sys)
    sys.setdefaultencoding('utf8')
    for i in range(len(result)):
        result[i] = (html.count(result[i]),result[i],i)

    result.sort(reverse=True)
    print(data["wd"])
    print("=============================================")
    for x in result:
        print(str(x[0])+" | "+x[1]+" | "+str(x[2]))
    print("=============================================")


    #开始点击答题
    click(config["tounaowangzhe"]["point"][int(result[0][2])])

这个代码的实现也只是我的一个思路。通过测试。还是发现很多问题。比如IO操作还是很影响性能。百度搜索并不是百分百的识别率和准确率。纯属娱乐一下。仅供大家参考。

 
注:本文内容均系原创。如需转载分享请标明出处。
posted at