在github上发现一个古老的华医网考试脚本(https://github.com/lhzzzzzz/autoexamofhuayi),是python2写的。它实现了华医网自动登录、自动获取考试编号cwid、自动考试。现在把它翻新一下。
基于已知的考试编号cwid,进行华医网自动考试。
1、Google Chrome;
2、Fiddler:用于抓包;
3、PyCharm
一、答题流程分析
已有现在的Javascript脚本(《华医网自动答题脚本》),根据华医网的答题代码,进行自动答题。但这个代码使用的是试错了,反复提交需要消耗时间,不适合批量操作。
根据GitHub现有脚本(https://github.com/lhzzzzzz/autoexamofhuayi),发现华医网是直接把原答案放在试题的网页中
所以其实在答题界面,用chrome的F12进行Inspect,也能找到正确答案。
name="gvQuestion$ctl03$result" 对应的 value即正确答案的value
通过Fiddler抓包可以看到,考试主要包括三个动作:
1、GET 考试试题
2、POST 考试试题+答案
3、GET 考试结果
而其中
POST答案提交的data包括以下几部分:
1、__EVENTTARGET 等是 ASP.Net 相关验证参数:可以从考试界面的网页中用正则表达式提取;其中留空的字段可以不提交
2、Hidden1、Hidden2、Hidden3:表示最前面的课程评价星级,可以不提交;
3、gvQuestion$ctl03$question_id、gvQuestion$ctl03$result、gvQuestion$ctl03$rbl :表示题号、正确选项、考生选项(这里当然是直接提交正确选项的value)
二、模拟登录华医网
根据旧的py脚本,以前的华医网登录不需要验证码,现在有了图片验证码,登录变得麻烦了。还是改成手动复制Fiddler抓到的cookie吧
参考:https://github.com/ZhaoKangming/Generate_CME_data_report/blob/master/get_cme_course_info.py
https://github.com/ZhaoKangming/HuaYi
三、Session会话保持
华医网登录之后使用Session进行对话,获取考卷、提交考试、获取成绩都会刷新cookie,而且只有最新的cookie能进行下次对话。
所以这里需要用requests.session()保持会话,而且起始的cookie必须是最新的一个cookie
# 原代码地址:https://github.com/lhzzzzzz/autoexamofhuayi
import requests
import re
# 设置Fiddler代理
proxies = {
"http": "http://127.0.0.1:8888",
"https": "http://127.0.0.1:8888",
}
session = requests.session()
# 打开 cookie.txt,复制最新一次对话的cookies
with open("cookie.txt", "r") as file:
cookie = file.read()
headers = {
'Accept': '*/*',
'Accept-Encoding': 'gzip, deflate',
'Accept-Language': 'zh-CN,zh;q=0.8',
'Connection': 'keep-alive',
'Host': 'cme3.91huayi.com',
'Content-Type': 'application/x-www-form-urlencoded',
'Upgrade-Insecure-Requests': '1',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'
}
headers['Cookie'] = cookie
session.headers = headers
def post_exam(cwid):
url = 'http://cme3.91huayi.com/pages/exam.aspx?cwid='+cwid
exam_content = session.get(url,proxies=proxies)
print(exam_content.text)
#选项name
pattern4 = re.compile(r'<input id="gvQuestion_rb.*?type="radio" name="(gvQuest.*?)".*?</label>')
match4 = re.findall(pattern4, exam_content.text)
match4_temp=[]
for item in match4: # 去重
if not item in match4_temp:
match4_temp.append(item)
match4 = match4_temp
# 隐藏答案
pattern5 = re.compile(r'<input type="hidden" name="(gvQuestion.*?)" id="gvQuestion.*?value="(.*?)" />')
match5 = re.findall(pattern5, exam_content.text)
pattern6 = re.compile(r'id="__VIEWSTATE" value=".*?/>')
match6 = re.findall(pattern6, exam_content.text)
pattern7 = re.compile(r'__EVENTVALIDATION" value=.*?/>')
match7 = re.findall(pattern7, exam_content.text)
exam_result = {
'__VIEWSTATE':match6[0].split('"')[3],
'__VIEWSTATEGENERATOR':'265B8D93',
'__EVENTVALIDATION':match7[0].split('"')[2],
'btn_submit.x':'0', # 系统用于检查用户有没有选择
'btn_submit.y': '20'
}
for ia in range(int(len(match5) / 2)):
print(ia)
exam_result[match4[ia]] = match5[ia*2][1] #rbl
exam_result[match5[ia*2][0]] = match5[ia*2][1]
exam_result[match5[ia*2+1][0]] = match5[ia*2+1][1]
headers['Referer'] = url
session.headers = headers
# 提交考试
r = session.post(url, data=exam_result,proxies=proxies)
# print(r.text)
# 获取考试结果
result = session.get('http://cme3.91huayi.com/pages/exam_result.aspx?cwid=' + cwid,proxies=proxies)
print(result.text)
cwids =[] # 考试id列表
for cwid in cwids:
print(cwid)
post_exam(cwid)
如果全部考完,可以在网页中看到可以申请证书。
华医网很多bug的,如没有完成考试也可以直接申请证书,在考试结果页面,浏览器状态输入代码就可以。
javascript: window.location.href = 'apply_certificate.aspx?cid=73058c85-868c-484c-b95d-a82dccfd468d'
联系客服