当前位置:   article > 正文

基于python的安全知识自动搜题_搜题 api

搜题 api

前言:

        近期学校要求强制去微信公众号小程序进行:安全知识答题,连续5天,每次25题,时间由10分钟逐级递减,感觉题量有点大,而且每天都要答题,所以我就在想有没有什么办法能进行自动答题,同时也可以来锻炼自己的技术,经过不断踩坑失败后,终于成功了。效果如下图所示:

前期思路: 

        1.selenium自动化:首先我想到的就是,能不能分享小程序链接,在网页做,可以用selenium来实现,不过我发现这个小程序链接根本就分享不了,这种方法直接pass。

        2.抓包:可以用一些抓包软件来抓包解析请求分析参数,但是难度肯定极高,而且说不定一堆反爬,鉴于我逆向基础较差这种方法pass

        3.用模拟器模拟手机,然后登陆微信进行操作,最后发现模拟器登陆微信打不开这个做题小程序,不知道是不是反扒措施,非常恼火。

解决办法:

        山穷水尽疑无路,柳暗花明又一村。经过一次次碰壁,我最终选择了一个最笨的办法:

        1.使用投屏软件将手机投屏到电脑屏幕上

        2.使用python的pyautogui库,将电脑截屏,刚好把题目截下来

        3.使用百度api图片文字识别技术,将截屏的问题识别出来

        4.获取题库,采用正则表达式将问题和答案保存进字典里

        5.根据问题和字典获取答案

 解决过程及代码:

1.使用投屏软件将手机投屏到电脑屏幕上

这里我使用的软件是todesk,手机和电脑各下载一个,就可以投屏了

 2.使用python的pyautogui库,将电脑截屏,刚好把题目截下来

其中(x1,y1)是左上角坐标, (x2,y2)是右下角坐标

  1. import pyautogui
  2. # 获取屏幕截图
  3. def save_screen(x1, y1, x2, y2):
  4. screenshot = pyautogui.screenshot()
  5. cropped_screenshot = screenshot.crop((x1, y1, x2, y2))
  6. cropped_screenshot.save('cropped_screenshot.png')
  7. save_screen(66, 400, 730, 1500)
  3.使用百度api图片文字识别技术,将截屏的问题识别出来 

        这里需要去百度智能云-登录注册账号,创建应用,把下面的api_key和secret_key换成自己的就行了

  1. import base64
  2. import urllib
  3. import requests
  4. API_KEY = "您的API_KEY "
  5. SECRET_KEY = "您的SECRET_KEY "
  6. def get_text(filaPath):
  7. url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=" + get_access_token()
  8. image = get_file_content_as_base64(filaPath, True)
  9. payload = f'image={image}'
  10. headers = {
  11. 'Content-Type': 'application/x-www-form-urlencoded',
  12. 'Accept': 'application/json'
  13. }
  14. response = requests.request("POST", url, headers=headers, data=payload)
  15. return response.text
  16. def get_file_content_as_base64(path, urlencoded=False):
  17. """
  18. 获取文件base64编码
  19. :param path: 文件路径
  20. :param urlencoded: 是否对结果进行urlencoded
  21. :return: base64编码信息
  22. """
  23. with open(path, "rb") as f:
  24. content = base64.b64encode(f.read()).decode("utf8")
  25. if urlencoded:
  26. content = urllib.parse.quote_plus(content)
  27. return content
  28. def get_access_token():
  29. """
  30. 使用 AK,SK 生成鉴权签名(Access Token)
  31. :return: access_token,或是None(如果错误)
  32. """
  33. url = "https://aip.baidubce.com/oauth/2.0/token"
  34. params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
  35. return str(requests.post(url, params=params).json().get("access_token"))
  36. get_text("images/2.png")
4.获取题库,采用正则表达式将问题和答案保存进字典里 

         这是一份题库,里面涵盖了绝大部分原题,不会写代码的把文字复制进文档,按ctrl+f搜索题也可以查到题和答案。

        也可以将下列文字保存进txt文件,然后使用正则表达式进行解析,由于题库格式问题我踩了不少坑,我列举一下我踩过的坑:

        我开始发现的规律是每道题都以 题号(数字)+开头 ,以  ()。结尾,所以我开始写的正则表达式就是        res = re.findall('\d{1,3}、(.*?)()。', text, re.S)        但是很快我就发现,匹配的少了几十道题,误差较大,在我仔细核对后发现:

        第一个坑:

        问题:有些题不以()。为结尾,这就导致很多题没匹配上

        解决方法:在我的一番观察后发现,虽然很多题空不在最后,但是每到题结束后肯定有选项吧,第一个选项就是选项A,改进后的代码: res = re.findall('\d{1,3}、(.*?)A', text, re.S) 确实多匹配到很多数据,但是还是有遗漏。

        第二个坑:

        问题:有些题不以 题号(数字)+开头,比如有的是题号(数字)+或者题号(数字)+空格

        解决方法res = re.findall('\d{1,3}[、\s \\.](.*?)A', text, re.S),这样不论是以 点 顿号 还是空格开头,都能匹配上了。

        第三个坑:

        问题:有些题的选项部分甚至没有ABCD,只有简单的换行,而且题目还有几十个,看到这我一下子就懵了,没办法题库质量太差了。

        解决方法res = re.findall('\d{1,3}[、\s \\.](.*?)答案', text, re.S),这样即使有的题没有abcd选项,至少有“参考答案”这几个字是全的(有的参考两个字都没有,所以我匹配的是答案)这样一下就能直接匹配一整道题,答案的匹配就容易很多了answer= re.findall('答案.*?(\w{1,7}\s', text, re.S)因为答案有单选和多选,而且有的多选很恶心中间放空格。

        第三个坑:

        问题:有些问题没有题号,导致无法匹配

        解决方法:这下真的没办法了,还好不是很多,只能一个一个去加了,如果大家有什么好办法欢迎来评论区讨论。

 5.根据问题和字典获取答案

        这里我将识别文本重新拼接了一下,可以直接返回第count张图片的问题

  1. def get_question(count):
  2. url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=" + get_access_token()
  3. image = get_file_content_as_base64(f"images/{count}.png", True)
  4. payload = f'image={image}'
  5. headers = {
  6. 'Content-Type': 'application/x-www-form-urlencoded',
  7. 'Accept': 'application/json'
  8. }
  9. response = requests.request("POST", url, headers=headers, data=payload)
  10. data = json.loads(response.text)
  11. words_result = data['words_result']
  12. question = ''
  13. flag = False
  14. for result in words_result:
  15. words = result['words']
  16. if '【判断】' in words or '【多选】' in words or '【单选】' in words:
  17. flag = True
  18. if flag:
  19. question += words
  20. if '()' in words:
  21. flag = False
  22. print('问题:', question)
  23. return question

结果如下: 

主函数如下:

1.首先加载保存好的字典

2.为了能够持续识别,采用while True循环

3.屏幕区域截图

4.通过截图获取问题

5.为了防止截图识别到的文字和题库有细微差别,这里我选取了识别到的问题中两个关键词,判断题库里的问题是否同时包含这俩关键词,如果同时包含,说明大概率就是这道题,输出问题以及结果就行。

优化思路:可以选用机器学习里的知识,求 截图问题的文本 所有题库里的问题 做相关性分析,进行排序找到相似度最高的,输出答案。

  1. def main():
  2. # 加载题库
  3. dan_xuan = load_answer('构建题库/单选.json')
  4. duo_xuan = load_answer('构建题库/多选.json')
  5. pan_duan = load_answer('构建题库/判断.json')
  6. x1, y1, x2, y2 = 66, 400, 730, 1500
  7. count = 0
  8. while True:
  9. s = input('是否继续?')
  10. count += 1
  11. save_screen(x1, y1, x2, y2, count)
  12. q = get_question(count)
  13. s1 = q[8:11]
  14. ss = q[-8:-4]
  15. print('关键词: ', s1, ss)
  16. print()
  17. if '【单选】' in q:
  18. for k, v in dan_xuan.items():
  19. if ss in k and s1 in k:
  20. print('搜索结果:'+k, '答案:'+v)
  21. if '【多选】' in q:
  22. for k, v in duo_xuan.items():
  23. if ss in k and s1 in k:
  24. print('搜索结果:' + k, '答案:' + v)
  25. if '【判断】' in q:
  26. for k, v in pan_duan.items():
  27. if ss in k and s1 in k:
  28. print('搜索结果:'+k, '答案:'+v)
  29. print('\n\n\n')

全部代码:

  1. import base64
  2. import json
  3. import urllib
  4. import pyautogui
  5. import requests
  6. API_KEY = "您的API_KEY "
  7. SECRET_KEY = "您的SECRET_KEY "
  8. def get_file_content_as_base64(path, urlencoded=False):
  9. with open(path, "rb") as f:
  10. content = base64.b64encode(f.read()).decode("utf8")
  11. if urlencoded:
  12. content = urllib.parse.quote_plus(content)
  13. return content
  14. def get_access_token():
  15. url = "https://aip.baidubce.com/oauth/2.0/token"
  16. params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
  17. return str(requests.post(url, params=params).json().get("access_token"))
  18. # 获取屏幕截图
  19. def save_screen(x1, y1, x2, y2, i):
  20. screenshot = pyautogui.screenshot()
  21. cropped_screenshot = screenshot.crop((x1, y1, x2, y2))
  22. cropped_screenshot.save(f'images/{i}.png')
  23. #加载json文件读取为字典
  24. def load_answer(fileName):
  25. with open(fileName, 'r') as file:
  26. data_dict = json.load(file)
  27. return data_dict
  28. #获取第i张图片的 问题 的文本
  29. def get_question(count):
  30. url = "https://aip.baidubce.com/rest/2.0/ocr/v1/accurate?access_token=" + get_access_token()
  31. image = get_file_content_as_base64(f"images/{count}.png", True)
  32. payload = f'image={image}'
  33. headers = {
  34. 'Content-Type': 'application/x-www-form-urlencoded',
  35. 'Accept': 'application/json'
  36. }
  37. response = requests.request("POST", url, headers=headers, data=payload)
  38. data = json.loads(response.text)
  39. words_result = data['words_result']
  40. question = ''
  41. flag = False
  42. for result in words_result:
  43. words = result['words']
  44. if '【判断】' in words or '【多选】' in words or '【单选】' in words:
  45. flag = True
  46. if flag:
  47. question += words
  48. if '()' in words:
  49. flag = False
  50. print('问题:', question)
  51. return question
  52. def main():
  53. # 加载题库
  54. dan_xuan = load_answer('构建题库/单选.json')
  55. duo_xuan = load_answer('构建题库/多选.json')
  56. pan_duan = load_answer('构建题库/判断.json')
  57. x1, y1, x2, y2 = 66, 400, 730, 1500
  58. count = 0
  59. while True:
  60. s = input('是否继续?')
  61. count += 1
  62. save_screen(x1, y1, x2, y2, count)
  63. q = get_question(count)
  64. s1 = q[8:11]
  65. ss = q[-8:-4]
  66. print('关键词: ', s1, ss)
  67. print()
  68. if '【单选】' in q:
  69. for k, v in dan_xuan.items():
  70. if ss in k and s1 in k:
  71. print('搜索结果:'+k, '答案:'+v)
  72. if '【多选】' in q:
  73. for k, v in duo_xuan.items():
  74. if ss in k and s1 in k:
  75. print('搜索结果:' + k, '答案:' + v)
  76. if '【判断】' in q:
  77. for k, v in pan_duan.items():
  78. if ss in k and s1 in k:
  79. print('搜索结果:'+k, '答案:'+v)
  80. print('\n\n\n')
  81. if __name__ == '__main__':
  82. main()

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/658763
推荐阅读
相关标签
  

闽ICP备14008679号