美文网首页程序员
自动刷题机 Python 解释源码 超新泛雅

自动刷题机 Python 解释源码 超新泛雅

作者: landmadename | 来源:发表于2017-09-17 11:30 被阅读0次

    本文解释一下代码,如果有想要用机器刷题的(前提是能找的到答案),可以参考一下。
    开发原因:作业又多又无聊自己不想做,干脆用机器刷题。
    主要方法:主要用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 type='ratio'>。但是并不是所有的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('<i class="fl">(\d*?)</i>[\s\S]*?【单选题】([\s\S]*?)</div>',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('<i class="fl">(\d*?)</i>[\s\S]*?【单选题】([\s\S]*?)</div>',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()
    

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

    相关文章

      网友评论

        本文标题:自动刷题机 Python 解释源码 超新泛雅

        本文链接:https://www.haomeiwen.com/subject/yksjsxtx.html