本文解释一下代码,如果有想要用机器刷题的(前提是能找的到答案),可以参考一下。

开发原因:作业又多又无聊自己不想做,干脆用机器刷题。

主要方法:主要用Python的selenium库实现刷题。

需要基础:Python你得会点吧 html你得会的吧 正则表达式你得会点吧

登录部分

导入以下包

from selenium import webdriver
#导入selenium的webdriver 如果这个看不懂的话请移步selenium教程
from fuzzywuzzy import fuzz
#计算相似度的工具,没听过也没关系,看到了自己查
import re
import random
定义一些变量
name='15000000'
#用户名
password='**********'
#密码
wrong=85
#准确率(百分比)
count=148
#总题数
wrong=count*(100-wrong)*0.01
#错题数
然后打开登录界面
dr=webdriver.Chrome()
#用chrome打开 Firefox同理
dr.get('http://passport2.chaoxing.com/login?fid=1400&refer=http://i.mooc.chaoxing.com/space/index.shtml')
自动输入用户名密码,手动输入验证码
dr.find_element_by_class_name("zl_input").send_keys(name)
dr.find_element_by_class_name("zl_input2").send_keys(password)
#上面是用class name定位的用户名密码位置(用F12找)
code=input('Verification code >>>')
dr.find_element_by_class_name("zc_input32").send_keys(code)
dr.find_element_by_class_name("zl_btn_right").click()
#手动输入验证码,并用相同方法填入,并点击登录

登录图

定位到作业部分

尝试点击《计算机网络基础》学测,(你会发现没用,待会解释为什么没用)

dr.find_element_by_xpath("/html/body/div/div[2]/div[2]/ul/li[2]/div[2]/h3/a").click()

#用xpath的方式定位超链接,并click。请自己补充一定的xpath知识。

下图是如何在chrome中找到元素xpath的方法(xpath 大概就是 一种唯一定位html元素的方式#我自己也不是很清楚)

image.png

用selenium定位元素是没有办法跨frame的,所以需要定位某元素时,dr必须在某frame中。所以需要找到对应的frame并层层切换过去。用F12找到课程所在frame的ID-->frame_content,然后

dr.switch_to_frame('frame_content')

#用这个方法切frame

dr.find_element_by_xpath("/html/body/div/div[2]/div[2]/ul/li[2]/div[2]/h3/a").click()

#再点击,会打开一个新标签页

打开新标签以后要把dr切换到新标签中

dr.switch_to_window(dr.window_handles[1])
#dr.window_handles是所有标签的句柄list

想办法点击进入题目页

hwxpath='/html/body/div[6]/div[1]/div[2]/div[3]/div/div[2]/h3/span[2]/a'
dr.find_element_by_xpath(hwxpath).click()
image.png

进去以后

image.png

处理题目

点进去以后发现 题目被三层frame嵌套所以要切进去:

dr.switch_to_frame(0)
dr.switch_to_frame(0)
dr.switch_to_frame(0)

#0就是切入当前frame下的第一个frame,虽然这样不是很规范,但是方便啊,无脑啊

好现在dr在题目的frame里了,现在要把所有的单选框放在一个列表里。我们用find_elements_by_tag_name方法(根据标签名寻找),因为所有的单选框都是。但是并不是所有的input标签都是单选框,看了看发现只有可见的input标签才是单选框。所以我们要做两件事,找到所有input,然后再在这里面挑出所有display的:

inputs=[]
for n in dr.find_elements_by_tag_name('input'):
if n.is_displayed():
inputs.append(n)
print(n,'ok')

上一步做完,所有的单选框都在inputs这个list里了,四个一组(ABCD)。然后用正则表达式从页面源码中提取出所有题目。

qs=re.findall('(\d*?)[\s\S]*?【单选题】([\s\S]*?)
',dr.page_source)


然后要找对应的答案,查了一下,发现,这个练习的所有题目来自一个题库,下载该题库,保存成answer.txt存在同一目录下。然后把问题和答案分别用正则表达式提取出来,一一对应。

image.png
with open(file,'r',encoding='utf-8') as f:
ass=f.read()
asq=re.findall('\d+ . (.*?)\n',ass)
asa=re.findall('答案:(.)',ass)

接下来就是匹配页面上的问题和下载的答案集了。但是因为页面源码和某些原因,题目可能会比答案多个空格少个字符什么的,所以有的时候不能完全匹配,就需要用模糊匹配和全匹配结合的方法。思路:先全匹配(因为快),如果不行,就计算两个题目的相似度,取相似度最高的。

asls=[]
for i in qs:
if i[1] in asq:
asls.append(asa[asq.index(i[1])])
else:
rls=[fuzz.ratio(i,ii) for ii in asq]
op=asa[rls.index(max(rls))]
asls.append(op)

#asls 里的结果大概就是这个样子['A','C','B'............'B']

然后我们要把所有的ABCD点上啊,第一个的A对应inputs里的0,B对应1......第二个的A对应4所以有公式——(ABCD的ASCII码-65+列表下标乘4)

asls=[ord(i)-65+e*4 for e,i in enumerate(asls)]

#列表推倒,不会的话自己用for写

#asls 里的结果大概就是这个样子[0,6,12........]

最后把inputs里的相应下标的inputs标签点击一下

for i in asls:
inputs[i].click()

当然,不能做全对吧,那就随机瞎点几个答案吧(错误率根据开始定义的错误率)

for i in range(int(wrong)):
random.choice(inputs).click()

全部解释完,撒花

下面贴全部源码

from selenium import webdriver
from fuzzywuzzy import fuzz
import re
import random
name='15000232'
password='a1008611'
wrong=85
count=148
wrong=count*(100-wrong)*0.01
dr=webdriver.Chrome()
dr.get('http://passport2.chaoxing.com/login?fid=1400&refer=http://i.mooc.chaoxing.com/space/index.shtml')
#open website
dr.find_element_by_class_name("zl_input").send_keys(name)
dr.find_element_by_class_name("zl_input2").send_keys(password)
code=input('Verification code >>>')
dr.find_element_by_class_name("zc_input32").send_keys(code)
dr.find_element_by_class_name("zl_btn_right").click()
#login
dr.switch_to_frame('frame_content')
dr.find_element_by_xpath("/html/body/div/div[2]/div[2]/ul/li[2]/div[2]/h3/a").click()
dr.switch_to_window(dr.window_handles[1])
#switch to frame and click 'SQL SERVER'
hwxpath='/html/body/div[6]/div[1]/div[2]/div[3]/div/div[2]/h3/span[2]/a'
dr.find_element_by_xpath(hwxpath).click()
dr.switch_to_frame(0)
dr.switch_to_frame(0)
dr.switch_to_frame(0)
inputs=[]
for n in dr.find_elements_by_tag_name('input'):
if n.is_displayed():
inputs.append(n)
print(n,'ok')
qs=re.findall('(\d*?)[\s\S]*?【单选题】([\s\S]*?)',dr.page_source)
file='answers.txt'
with open(file,'r',encoding='utf-8') as f:
ass=f.read()
asq=re.findall('\d+ . (.*?)\n',ass)
asa=re.findall('答案:(.)',ass)
asls=[]
for i in qs:
if i[1] in asq:
asls.append(asa[asq.index(i[1])])
else:
rls=[fuzz.ratio(i,ii) for ii in asq]
op=asa[rls.index(max(rls))]
asls.append(op)
asls=[ord(i)-65+e*4 for e,i in enumerate(asls)]
for i in asls:
inputs[i].click()
for i in range(int(wrong)):
random.choice(inputs).click()

当然你们做的题和我的不一样,所以要自己改改,这个程序并不是很健全,因为我懒就这样。