从0到1使用python开发一个半自动答题小程序的实现

前言

最近每天都有玩微信读书上面的每日一答的答题游戏,完全答对12题后,可以瓜分无限阅读卡。但是从小就不太爱看书的我,很难连续答对12道题,由此,产生了写一个半自动答题小程序的想法。我们先看一张效果图吧(ps 这里主要是我电脑有点卡,点击左边地选项有延迟)

项目GIthub地址:微信读书答题python小程序

觉得对你有帮助的请点个⭐来支持一下吧。

演示图:

做前准备

  • mumu模拟器 因为手边没有安卓手机,所以只能在模拟器上进行模拟,如果手上有安卓手机地,可以适当地修改一下程序。需要安装微信和微信读书这两个软件
  • python工具包:BeautifulSoup4、Pillow、urllib、requests、re、base64、time

思路

  • 截屏含有题目和答案的图片(范围可以自己指定)
  • 使用百度的图片识别技术将图片转化为文字,并进行一系列处理,分别将题目和答案进行存储
  • 调动百度知道搜索接口,将题目作为搜索关键字进行答案搜索
  • 将搜索出来的内容使用BeautifulSoup4进行答案提取,这里可以设置答案提取数量
  • 将搜索结果进行输出显示

附:这里我还加了一个自动推荐答案,利用百度短文本相似接口和选项是否出现在答案中这两种验证方法进行验证,推荐相似度最高的答案。准确度还可以,但是比较耗时间,比正常情况下时间要多上一倍。

开始写代码

1. 导入工具包

import requests #访问网站
import re		#正则表达式匹配
import base64	#编码
from bs4 import BeautifulSoup #处理页面数据
from urllib import parse #进行url编码
import time #统计时间
from PIL import ImageGrab #处理图片

2. 编写类和初始化方法

class autogetanswer():
  def __init__(self,StartAutoRecomment=True,answernumber=5):
    self.StartAutoRecomment=StartAutoRecomment
    self.APIKEY=['BICrxxxxxxxxNNI','CrHGxxxxxxxx3C']
    self.SECRETKEY=['BgL4jxxxxxxxxxGj9','1xo0jxxxxxx90cx']
    self.accesstoken=[]
    self.baiduzhidao='http://zhidao.baidu.com/search?'
    self.question=''
    self.answer=[]
    self.answernumber=answernumber
    self.searchanswer=[]
    self.answerscore=[]
    self.reanswerindex=0
    self.imageurl='answer.jpg'
    self.position=(35,155,355,680)
    self.titleregular1=r'(10题|共10|12题|共12|翻倍)'
    self.titleregular2=r'(\?|\?)'
    self.answerregular1=r'(这题|问题|跳题|换题|题卡|换卡|跳卡|这有)'
  • self.StartAutoRecomment 是否开启自动推荐答案,默认为True
  • self.APIKEY 百度图像转文字、百度短文本相似度分析 这两个接口的apikey
  • self.SECRETKEY 百度图像转文字、百度短文本相似度分析 这两个接口的secretkey

这两个key值我就没法提供给大家了,大家可以自己去百度云官方申请,免费额度大概有5万,足够我们使用了。

申请过程大家可以参考这个博客,很简单的如何申请百度文字识别apikey和Secret Key

  • self.accesstoken 存储申请使用接口的accesstoken值
  • self.baiduzhidao 百度知道搜索接口地址
  • self.imageurl 图片地址
  • self.position 截图方位信息,依次分别是左间距、上间距、右间距、下间距
  • self.titleregular1、.titleregular2、answerregular1 这些是进行题目和答案处理的条件

3. 获得accesstoken值

 def GetAccseetoken(self):
    for i in range(len(self.APIKEY)):
      host = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id={}&client_secret={}'.format(self.APIKEY[i],self.SECRETKEY[i])
      response = requests.get(host)
      jsondata = response.json()
      self.accesstoken.append(jsondata['access_token'])

这是官方提供的获取accesstoken的摸板,大家直接使用就行了。

4. 图像转文字以及相关处理

 def OCR(self,filename):
    request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate_basic"
    # 二进制方式打开图片文件
    f = open(filename, 'rb')
    img = base64.b64encode(f.read())
    params = {"image":img}
    access_token = self.accesstoken[0]
    request_url = request_url + "?access_token=" + access_token
    headers = {'content-type': 'application/x-www-form-urlencoded'}
    response = requests.post(request_url, data=params, headers=headers)
    #===上面是使用百度图片转文字接口转化,返回格式为json
    if response:
      result = response.json()
      questionstart=0
      answerstart=0
      self.question=''
      self.answer=[]
      #确定题目和答案所在的位置
      for i in range(result['words_result_num']):
        if(re.search(self.titleregular1,result['words_result'][i]['words'])!=None):
          questionstart=i+1
        if(re.search(self.titleregular2,result['words_result'][i]['words'])!=None):
          answerstart=i+1
       #下面是进行题目和答案的处理
      if(answerstart!=0):
        for title in result['words_result'][questionstart:answerstart]:
          if(re.search(self.answerregular1,title['words'])!=None):
            pass
          else:
            self.question+=title['words']
        for answer in result['words_result'][answerstart:]:
          if(re.search(self.answerregular1,answer['words'])!=None):
            pass
          else:
            if(str(answer['words']).find('.')>0):
              answer2 = str(answer['words']).split('.')[-1]
            else:
              answer2=answer['words']
            self.answer.append(answer2)
      else:
        for title in result['words_result'][questionstart:]:
          if(re.search(self.answerregular1,title['words'])!=None):
            pass
          else:
            self.question+=title['words']
      print("本题问题:",self.question)
      print("本题答案:",self.answer)
    return response.json()#可有可无

此方法是将图片转化为文字,进行图片中的文字识别,格式如下:

{
  "log_id": 2471272194,
  "words_result_num": 2,
  "words_result":
	  [
		  {"words": " TSINGTAO"},
		  {"words": "青島睥酒"}
	  ]
}

下面我们以下面的图为例,我们是如何去除掉干扰信息的:

上图就是程序在实际运行中的情况,黄色框内就是程序截取的图像(这个通过初始化方法的参数中的position可以进行设置),

我们需要的是红色框内的信息,这包含题目和答案选项。文字识别后,白色框里面的字也会和红色框里的字一同被识别,并以json形式输出,这些信息对我们就是干扰信息,所以,我通过建立了初始化方法里titleregular1、titleregular2、answerregular1 这三个标准进行判定,白色框里的文字与对应,如果判断包含的话,就不添加到题目中或者答案中。

5. 百度知道进行答案搜索

 def BaiduAnswer(self):
    request = requests.session()
    headers={'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36'}
    data = {"word":self.question}
    url=self.baiduzhidao+'lm=0&rn=10&pn=0&fr=search&ie=gbk&'+parse.urlencode(data,encoding='GB2312')
    ress = request.get(url,headers=headers)
    ress.encoding='gbk'
    if ress:
      soup = BeautifulSoup(ress.text,'lxml')
      result = soup.find_all("dd",class_="dd answer")
      if(len(result)!=0 and len(result)>self.answernumber):
        length=5
      else:
        length=len(result)
      for i in range(length):
        self.searchanswer.append(result[i].text)

这里是模拟浏览器进行百度知道搜索答案,将返回的文本交给BeautifulSoup进行处理,提取出我们需要的部分。后面最后几句有一个判定,如果查询到的答案数量超过我们设置的答案数,比如是5,那么就将前5个答案放入searchanswer列表中,如果查询到的答案数量要少于我们设置的,返回所有答案。

6. 短文本相似度分析

def CalculateSimilarity(self,text1,text2):
    access_token = self.accesstoken[1]
    request_url="https://aip.baidubce.com/rpc/2.0/nlp/v2/simnet"
    request_url = request_url + "?access_token=" + access_token
    headers = {'Content-Type': 'application/json'}
    data={"text_1":text1,"text_2":text2,"model":"GRNN"}
    response = requests.post(request_url, json=data, headers=headers)
    response.encoding='gbk'
    if response:
      try:
        result = response.json()
        return result['score']
      except:
        return 0

这里调用的是百度短文本相似度分析的接口,用于分析选项与查询到的答案的相似度,以此来推荐一个参考答案。这个是官方给的摸板,直接调用,更换一下参数即可。

7. 自动给出一个参考答案

 def AutoRecomment(self):
    if(len(self.answer)==0):
      return
    for i in range(len(self.answer)):
      scores=[]
      flag=0
      for j in range(len(self.searchanswer)):
        if(j!=0and (j%2==0)):
          time.sleep(0.1)
        score = tools.CalculateSimilarity(tools.answer[i],tools.searchanswer[j])
        if(tools.answer[i] in tools.searchanswer[j]):
          score=1
        scores.append(score)
        if(score>0.8):
          flag=1
          self.answerscore.append(score)
          break
      if(flag==0):
        self.answerscore.append(max(scores))
    self.reanswerindex = self.answerscore.index(max(self.answerscore))

这里调用了咱们第六步的CalculateSimilarity()方法,统计每一个选项与搜索到的答案相似度,取最高的存入answerscore列表中。这里我又加了一个操作,我发现这个相似度匹配有时正确率比较低,所以这里加了一个判定,若选项在搜索到的答案中出现,给予一个最大相似值,也就是1,这就大大提高了推荐的准确度。

8. 初始化参数

def IniParam(self):
    self.accesstoken=[]
    self.question=''
    self.answer=[]
    self.searchanswer=[]
    self.answerscore=[]
    self.reanswerindex=0

相关参数的初始化,因为每进行完一道题,要对存储题和答案以及相关信息的数组进行清空,否则会对后面题的显示产生影响。

9. 主方法

def MainMethod(self):
    while(True):
      try:
        order = input('请输入指令(1=开始,2=结束):')
        if(int(order)==1):
          start = time.time()
          self.GetAccseetoken()
          img = ImageGrab.grab(self.position)#左、上、右、下
          img.save(self.imageurl)
          self.OCR(self.imageurl)
          self.BaiduAnswer()
          if(self.StartAutoRecomment):
            self.AutoRecomment()
          print("======================答案区======================\n")
          for i in range(len(self.searchanswer)):
            print("{}.{}".format(i,self.searchanswer[i]))
          end = time.time()
          print(self.answerscore)
          if(self.StartAutoRecomment and len(self.answer)>0):
            print("\n推荐答案:",self.answer[self.reanswerindex])
          print("\n======================答案区======================")
          print("总用时:",end-start,end="\n\n")
          self.IniParam()
        else:
          break
      except:
        print("识别失败,请重新尝试")
        self.IniParam()
        pass

这里主要是一个while循环,通过输入指定来判断是否结束循环。

这里说一下下面这两个语句:

img = ImageGrab.grab(self.position)#左、上、右、下
img.save(self.imageurl)

这两个语句是用来截取我们指定位置的图片,然后进行图片的保存。

总结

上述呢,就是整个项目完成的流程,整体运行是几乎每什么问题,但是还是存在许多可优化的空间。也欢迎大家对此感兴趣的留言,说说你的改进意见,我会非常感谢,并认真考虑进去。期待与大家的讨论!😄

到此这篇关于从0到1使用python开发一个半自动答题小程序的实现的文章就介绍到这了,更多相关python 半自动答题小程序内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • python实现抽奖小程序

    本文实例为大家分享了python实现抽奖小程序的具体代码,供大家参考,具体内容如下 设计一个抽奖服务  背景:有x个奖品,要求在y天内发完:每天至少发放z个奖品:每天抽奖人数不定,事先会假设一个范围是m-n 举例:有100个奖品,要求5天内发完,每天至少发15个奖品:每天来抽奖的人估计是 2000-3000 人,希望奖品能够比较均匀,但随机的抽取出来. 接口要求:服务监听一个端口,测试程序不断连接,发送一个数字代表是第几天,比如第1-2000个请求发送1(模拟第一天来了2000人),第2001到

  • Python实现的检测web服务器健康状况的小程序

    对web服务器做健康检查,一般我们都是用curl库(不管是php,perl的还是shell的),大致的方法一致: 复制代码 代码如下: curl -I -s www.qq.com  |head -1|awk '{ health = $2=="200"?"server is ok":"server is bad"}END{print health}' server is ok 说白了这些方式都是封装了curl库的,另外还有一些关于http的模块,例

  • Python实现注册、登录小程序功能

    主要实现功能 1.用户输入用户名,在用户名文件中查找对应的用户,若无对应用户名则打印输入错误 2.用户名输入正确后,进行密码匹配.输入密码正确则登录成功,否则重新输入. 3.连续输错三次密码则该用户名被锁,退出程序 -------------------------------------------------- 在程序文件夹下建立一个用户名.密码的文件 :user_np.txt和一个用于存放被锁用户名的文件:lock.txt ---------------------------------

  • python实现日常记账本小程序

    python实现收支的自动计算,能够查询每笔账款的消费详情,具体内容如下 1.函数需要两个文件:一个类似钱包功能,存放钱:另一个用于记录每笔花销的用途 #!/usr/bin/env python import cPickle as p with open('wallet.data','w') as f: p.dump(10000,f) with open('record.txt','w') as f: pass 2.功能实现 #!!/usr/bin/env python #coding:utf8

  • 基于腾讯云服务器部署微信小程序后台服务(Python+Django)

    一 前言 微信小程序,相信大家早已熟知,它是一种无需下载安装即可使用的轻型应用,具有跨平台和接近 Native App 性能体验的优势.从开发模式上说,它是前后端分离的,微信小程序负责实现前端应用,后端服务可以使用任何你说熟知的开发语言,如 PHP . NodeJs . Java . C# . Python 等,因而,微信小程序的开发文档主要是围绕 WXML . WXSS 等前端框架.组件或样式布局进行讲解,几乎看不到后端技术的身影.本文主要介绍如何在腾讯云服务器上部署 Python+Djang

  • 一个计算身份证号码校验位的Python小程序

    S = Sum(Ai * Wi), i=0,.......16 (现在的身份证号码都是18位长,其中最后一位是校验位,15位的身份证号码好像不用了) Ai对应身份证号码,Wi则为用于加权计算的值,它一串固定的数值,应该是根据某种规则得出的吧,用于取得最好的随机性,Wi的取之如下: 7   9 10 5 8   4   2   1 6   3   7   9 10  5   8   4   2 经过加权计算之后,得到一个S,用这个S去模11,取余值,然后查表得到校验位,这个索引表如下: 0 ---

  • Python实现比较扑克牌大小程序代码示例

    是Udacity课程的第一个项目. 先从宏观把握一下思路,目的是做一个比较德州扑克大小的问题 首先,先抽象出一个处理的函数,它根据返回值的大小给出结果. 之后我们在定义如何比较两个或者多个手牌的大小,为方便比较大小,我们先对5张牌进行预处理,将其按照降序排序,如下: def card_ranks(hand): ranks = ['--23456789TJQKA'.INDEX(r) for r, s in hand] ranks.sort(reverse=True) return ranks 然后

  • python实现聊天小程序

    本文实例为大家分享了python实现聊天小程序的具体代码,供大家参考,具体内容如下 我这里实现的是客户端与服务端进行通信的功能,比较简单,与上一篇文章的群聊不太一样. 服务端server.py #-*- coding:utf-8 -*- import socket, traceback, sys host = '' port = 51423 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.setsockopt(socket.SOL_

  • python编写爬虫小程序

    起因 深夜忽然想下载一点电子书来扩充一下kindle,就想起来python学得太浅,什么"装饰器"啊."多线程"啊都没有学到. 想到廖雪峰大神的python教程很经典.很著名.就想找找有木有pdf版的下载,结果居然没找到!!CSDN有个不完整的还骗走了我一个积分!!尼玛!! 怒了,准备写个程序直接去爬廖雪峰的教程,然后再html转成电子书. 过程 过程很有趣呢,用浅薄的python知识,写python程序,去爬python教程,来学习python.想想有点小激动--

  • python 提取文件的小程序

    以前提取这些文件用的是一同事些的批处理文件:用起来不怎么顺手,刚好最近在学些python,所有就自己动手写了一个python提取文件的小程序:1.原理 提取文件的原理很简单,就是到一个指定的目录,找出最后修改时间大于给定时间的文件,然后将他们复制到目标目录,目标目录的结构必须和原始目录一致,这样工程人员拿到后就可以直接覆盖整个目录: 2.实现 为了程序的通用,我定义了下面的配置文件 config.xml 复制代码 代码如下: <?xml version="1.0" encodin

  • 有趣的python小程序分享

    python可以简单优美,也很有趣,下面是收集的例子: 1.一句话开始一个http的文件服务器: $ python -m SimpleHTTPServer Serving HTTP on 0.0.0.0 port 8000 ... 在浏览器中就可以http://localhost:8000访问目录及文件了. 也可以直接指定端口: $ python -m SimpleHTTPServer 6666 如果想在代码中实现,也很简单: import SimpleHTTPServer import Soc

随机推荐