v-1.0 少年, 快送自己一个青马易战自动答题机吧!
免责声明: 本文仅为个人学习交流日志, 禁止复制/下载等内容迁移行为!
起因
又是网课摸鱼的一天, 我在QQ空间上冲浪, 突然刷到同学转发的”青马易战代刷”. 只要支付7R~12R, 对方就会帮你刷完一科500题的青马易战.
哦, 我才突然想起来还有这么一个作业要做, “其实青马的题挺好做的, 500题也就是一天半天的样子.”—来自其他同学. 那其实自己做也没什么大不了的嘛, 何必请人去刷呢.
当我亲自做过大半百题后终于醒悟, 自己还是年轻了. 青马易战的题目并不好做, 需要不浅的知识储备. 少年, 快送自己一个青马易战自动答题机吧! 果然比起交钱给别人, 还是用自己双手解决作业更加殷实.
简单搜索之后, 喜得前辈真传.
青马易战解决方案-QingmaKiller - Tawn's Blog
python实现青马易站自动刷题_跳墙网
理论存在, 实践开始! 虽然前辈说的东西完全没有接触, 但是看起来不难, 似乎是爬虫技术? 那就开学吧!
2021年最新Python爬虫教程+实战项目案例(最新录制)_哔哩哔哩_bilibili
前置
HTTP
当你与网页交互时, 浏览器会通过http协议与服务器沟通, 你说你想要的, 然后服务器发给你想要的.
你发出去的叫请求报文, 请求报文由三个部分构成:
请求行 -> 请求方式 请求url地址 协议
首部行 -> 附加信息
请求体 -> 请求参数
你接受到的叫响应报文, 响应报文由三个部分构成:
状态行 -> 协议 状态码
首部头 -> 附加信息
响应体 -> 响应数据
其中比较重要的是首部行中的:
User-Agent: 你的访问设备, 记得伪装成手机哦
cookie: 用户的登入信息, 就是标识你是你啦
想要监控访问过程的报文可以直接浏览器’右键→检查→网络’查看
Untitled
Untitled
Python
不会Python怎么办? 菜鸟速通看一看! Python支持中文变量真的很棒.
只要了解一下基础的流程控制就好了. 然后了解一下字典/JSON/文件操作, 用来存储答案.
Python3 教程 | 菜鸟教程
Python Requests
选用Python的原因就在于此了, Requests可以非常方便的用来发送THHP请求
记得伪装吗, 先定义一下首部行
1 2 3 4 header = { "User-Agent" : "XXX" , 'Cookie' : "XXX" }
然后就可以访问网站啦
1 2 res = requests.get(url = url, headers = header, params=param) res = requests.post(url = url, headers = header, data = data)
用JSON提取出响应报文中的数据
1 2 3 import json数据 = json.loads(res.text)
正则表达式
拿到网页之后会需要从中找到的内容
开发
获取cookie
参考了前辈的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 def updateCookie (self ): headers = { 'Accept-Encoding' : 'gzip, deflate' , 'Accept-Language' : 'zh-CN,zh;q=0.9' , 'Host' : 'qm.linyisong.top' , 'Proxy-Connection' : 'keep-alive' , 'Upgrade-Insecure-Requests' : '1' , 'User-Agent' : 省略 } res = requests.get(self .url, headers=headers) headers['Cookie' ]=re.match (r'JSESSIONID=\w*' ,res.headers['set-cookie' ]).group() res = requests.get(self .url, headers=headers) self .cookie=headers['Cookie' ] print ('成功取得cookie' ) print (self .cookie) res.close()
捕获通信
先随便开一门做两题, 监控一下网络通信
发现主要有两个通信行为, 一个nextSubject, 一个changeSituation, 看一下.
在nextSubject里
请求头
1 2 3 4 5 6 7 8 9 10 11 12 POST /yiban-web/stu/nextSubject.jhtml?_=省略 HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 ,en;q=0.8 Content-Length: 10 Content-Type : application/x-www-form-urlencoded Cookie: 省略 Host: qm.linyisong.top Origin: http://qm.linyisong.top Proxy-Connection: keep-alive Referer: http://qm.linyisong.top/yiban-web/stu/toSubject.jhtml?courseId=7 User-Agent: 省略
请求参数
响应数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 { "data" : { "nextSubject" : { "courseId" : 7 , "option0" : "主张统一" , "option1" : "主张独立" , "option2" : "不统不独" , "option3" : "一国两府" , "optionCount" : 4 , "score" : 1 , "subDescript" : "当前国民党对两岸关系是" , "subType" : "单选题" , "timeLimit" : 60 }, "uuid" : 省略 }, "isSuccess" : true }
在changeSituation里
请求头
1 2 3 4 5 6 7 8 9 10 11 12 POST /yiban-web/stu/changeSituation.jhtml?_=省略 HTTP/1.1 Accept: application/json Accept-Encoding: gzip, deflate Accept-Language: zh-CN,zh;q=0.9 ,en;q=0.8 Content-Length: 69 Content-Type : application/x-www-form-urlencoded Cookie: 省略 Host: qm.linyisong.top Origin: http://qm.linyisong.top Proxy-Connection: keep-alive Referer: http://qm.linyisong.top/yiban-web/stu/toSubject.jhtml?courseId=7 User-Agent: 省略
请求参数
1 2 3 answer: A courseId: 7 uuid: 省略
响应数据
1 2 3 4 5 6 7 8 { "data" : { "rightAnswer" : false, "rightOption" : "C.不统不独" }, "isSuccess" : true, "message" : "回答错误!" }
分析通信
多做几题对比之后, 可以发现:
请求行中的数字是时间戳
同样参考前辈的函数获取时间戳
1 2 3 4 5 6 7 def getTime (): t = str (time.time()) a = str (t[0 :10 ]) b = str (t[11 :14 ]) res = a + b return res
使用courseId请求题目
在请求题目时, 只要在参数附带courseId就可以得到完整的题目报文, 包括题面选项和类型
1 2 3 4 5 6 7 8 看题链接 = 'http://qm.linyisong.top/yiban-web/stu/nextSubject.jhtml?_={}' .format (getTime()) headers = { 'Cookie' : cookie, } 让我看看 = { 'courseId' : courseId } res = requests.post(看题链接, headers = headers, data = 让我看看)
在响应报文里我们可以得到我们想要的题目和下面要用到的UUID
1 2 uuid = json.loads(res.text)['data' ]['uuid' ] 题目 = json.loads(res.text)['data' ]['nextSubject' ]
使用UUID回答题目
在回答题目时, 需要在参数中附带答案, courseId和UUID
答案只是ABCD, 即使是判断题, 也是用AB表示的
courseId直接同科目即可
UUID是题目报文中的一部分, 从中获取
1 2 3 4 5 6 7 8 9 10 答题链接 = 'http://qm.linyisong.top/yiban-web/stu/changeSituation.jhtml?_={}' .format (getTime()) headers = { 'Cookie' : cookie, } 让我猜猜 = { 'answer' : 答案, 'courseId' : courseId, 'uuid' : uuid } res_ = requests.post(答题链接, headers = headers, data = 让我猜猜)
在响应报文里我们可以得到正确答案和作答情况
1 2 正确答案 = json.loads(res_.text)['data' ] 作答情况 = json.loads(res_.text)['message' ]
正确做题
既然我们可以得到完整题目和正确答案, 又能提交自己想要的答案, 那么就可以收集题库了, 然后在做题时到题库中检索, 如果有答案就回答正确答案, 没有答案就随便回答一个吧
查询答案
用题目和答案建立一个字典, 然后在字典里查
这部分也不知道在使用Python时怎样更高效, 有大佬可以教教QWQ
1 2 3 4 5 6 7 8 if 题目 in 题库: print ('匹配答案!' ) 答案 = 题库[题目] 匹配到答案 = 1 else : print ('没有答案!' ) 答案 = 'A' 匹配到答案 = 0
录入题库
把获取到的题目写入文件本地保存
1 2 3 4 5 6 7 if 匹配到答案 == 0 : 新题目 = {题目,正确答案} with open ('database_{}.json' .format (courseId), 'a+' , encoding="utf-8" ) as f: json.dump(新题目, f, ensure_ascii=False ) f.write('\n' ) f.close() print ('题目入库!' )
加载题库
把本地文件加载成题库
1 2 3 4 5 6 题库 = {} with open ('database_{}.json' .format (courseId), 'r' , encoding="utf-8" ) as f: for line in f.readlines(): 题目 = json.loads(line) f.close() print ('-->题库预载成功,有题目:' +str (len (题库))+'道<--' )
自动化
最后, 把上述零件进行一个拼接就可以运行啦!
收集足够多的题目即可保证正确率.
后记
这是一次成果导向的学习, 不得不说在一个目标的指引下, 人会非常有动力. 不过迷茫也是真的迷茫, 全程百度和问人: “啊你会Python吗?”. 哈哈哈.
从上午十点钟有想法开始, 一直做到了凌晨三点, 晚饭甚至也不记得吃了奶茶没忘记喝, 虽然效率很低, 但是成就感很足.
在最后的凌晨几个小时里, 就是不断地调试一些BUG和优化打包了, 包括网络问题和文件读写, 就留给读者自己尝试吧.
虽然我是从不想给别人交钱开始, 但是在成品完成之后, 也有了商业化的想法, 但是果然还是太麻烦了吧, 我不想和陌生人讲话.
最后感谢前辈的文章, 首先可行先给我信心, 然后内容也给我帮助, 大佬太多啦, 我还是要努力才行.