教務(wù)處考試系統(tǒng)自動答題

學(xué)校要求登錄教務(wù)處網(wǎng)站做一個測試題,我做了看了看,30分鐘300道題,240分幾個,題量不少,題還不好做。研究了一下發(fā)現(xiàn)原來在網(wǎng)站上就有題庫的,但是一道題只有6s 的時間作答,邊查邊做肯定是時間不夠的。靈光一閃,人生苦短,我用Python,寫個自動答題的機(jī)器人吧。


思路:

  • 爬取題庫并存儲到數(shù)據(jù)庫
  • 模擬登錄教務(wù)系統(tǒng)
  • 進(jìn)入答題頁面,遍歷題目,匹配數(shù)據(jù)庫中記錄,給出答案
  • 提交數(shù)據(jù)

用到的工具:

  • Python
  • requests
  • BeautifulSoup
  • mongodb

實(shí)現(xiàn)過程:

  • 模擬登錄

以前研究過學(xué)校教務(wù)系統(tǒng)的登錄,現(xiàn)在終于在正事上排上用場了。學(xué)校教務(wù)系統(tǒng)的登錄還算簡單,沒有驗(yàn)證碼,唯一一點(diǎn)兒小障礙是登錄表單會有幾個隱藏字段,有個字段會動態(tài)改變,解決就是先GET一下登錄網(wǎng)址,獲取這幾個字段的值,再隨表單進(jìn)行POST。代碼:

import requests
from bs4 import BeautifulSoup
import os

headers = {
    'Connection': 'keep-alive',
    'Cache-Control': 'max-age=0',
    'Upgrade-Insecure-Requests': '1',
    'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.95 Safari/537.36',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
    'Accept-Encoding': 'gzip, deflate, sdch',
    'Accept-Language': 'zh-CN,zh;q=0.8,en;q=0.6,zh-TW;q=0.4'
}

session = requests.session()

# 先GET一下登錄頁面獲得隱藏字段
resp = session.get("http://ids.qfnu.edu.cn/authserver/login?service=http%3A%2F%2F202.194.188.19%2Fcaslogin.jsp", headers=headers)
bsObj = BeautifulSoup(resp.text, "html.parser")     
lt = bsObj.find('input', {'name':'lt'})['value']
execution = bsObj.find('input', {'name':'execution'})['value']

params = {
    'username': os.environ.get('STU_ID'),   # 環(huán)境變量獲取的學(xué)號
    'password': os.environ.get('STU_PWD'), # 環(huán)境變量獲取的密碼
    'lt': lt,
    'execution': execution,
    '_eventId': 'submit',
    'rmShown': '1'
}

# post 數(shù)據(jù)登錄成功
resp = session.post("http://ids.qfnu.edu.cn/authserver/login?service=http%3A%2F%2F202.194.188.19%2Fcaslogin.jsp", data=params, headers=headers)

  • 題庫爬取

用了Python的requests庫進(jìn)行頁面的爬取,勵志小哥寫的這個庫的確好用,特別是運(yùn)用 requests.session()之后,處理好登錄之后,再也不用管那些煩人的cookie 啥的了,用了BeautifulSoup來進(jìn)行頁面解析,用起來也是很順手。開始有亂碼,一看網(wǎng)頁編碼是gb2312的,稍微設(shè)置一下也OK了。
內(nèi)容有了,當(dāng)然要存儲起來了,不然每次答題都有爬題庫多麻煩,何況是些千年不變的東西。開始用的是MySQL,然而編碼問題讓人頭疼,設(shè)置編碼為gb2312,存儲的時候說有內(nèi)容 gb2312 又解析不了,于是程序就掛了。搞了很長時間也沒搞定,還把我的 Sequel Pro 給搞掛了,f***!
靜下心來一想,題庫只要寫數(shù)據(jù)庫寫一遍就OK了,但是答題的時候會頻繁地查詢數(shù)據(jù)庫,用nosql數(shù)據(jù)庫多好。題目做鍵,答案做值就行了??催^redis,但畢竟是內(nèi)存型數(shù)據(jù)庫,雖然快,但是還要做持久化,直接用mongodb吧,還沒看過,剛好學(xué)習(xí)了,邊學(xué)邊用。
爬取并存儲題庫部分的代碼:

tikubhs = [8692, 10988, 10989, 10990, 10991, 10992, 10993, 10994, 10995]  # 每一類題庫的編號
pages = [153, 77, 13, 18, 22, 27, 10, 39, 12]  # 每一個題庫的題目頁數(shù)

from pymongo import MongoClient
client = MongoClient()
db = client.shitiDB    # 數(shù)據(jù)庫名 shitiDB

shiti_table = db.shitis    # 表名 shitis

for tikubh, page_range in zip(tikubhs, pages):
    for page in range(1, page_range+1):
        url = "http://aqjy.qfnu.edu.cn/redir.php?catalog_id=6&cmd=learning&tikubh="+str(tikubh)+"&page="+str(page)
        resp = session.get(url)
        resp.encoding = 'gb2312'
        bsObj = BeautifulSoup(resp.text, "html.parser")
        shitis = bsObj.find_all('div', class_='shiti')
        daans = bsObj.find_all('span', style='color:#666666')
        values = []
        for timu_str, daan_str in zip(shitis, daans):
            shitibh = int(timu_str.h3.text[0:5])
            timu = timu_str.h3.text[6:]
            daan = daan_str.text[daan_str.text.find('標(biāo)準(zhǔn)答案')+5:].strip(' )')
            d = {'shitibh':shitibh, 'tikubh':tikubh, 'timu':timu, 'daan':daan}
            values.append(d)
        new_result = shiti_table.insert_many(values)

  • 模擬作答

這一部分是最關(guān)鍵的部分,再這上面的耗時比較多,大部分時間都在研究他的數(shù)據(jù)的提交流程。
題目是分頁的,且選擇頁面或點(diǎn)擊上下頁的時候,地址欄的地址是不變的,說明分頁是通過js實(shí)現(xiàn)的,而不是直接用的鏈接:


研究得知,上下頁和頁面選擇都是通過post數(shù)據(jù)標(biāo)志到本頁面實(shí)現(xiàn)的

搞懂了這些數(shù)據(jù)的意義和他們之間的關(guān)系,用代碼模擬出來就OK了,當(dāng)作到最后一頁完成的時候,把tijiao標(biāo)志也設(shè)為1,POST到原URL就完成了作答,這部分代碼就不貼了,文末有GitHub鏈接。

  • 可能的改進(jìn)

    • 寫好之后許多同學(xué)找我給答題,看看如果多的話用flask搭成個web服務(wù)。高效還不用擔(dān)心我泄露你們的密碼了。
    • 爬題庫的時候想的是爬答案的文本,爬成了ABCD的選項(xiàng),多虧選項(xiàng)和答案文本的對應(yīng)關(guān)系沒變,但也造成個別問題答案會有錯誤,致使我給答題的同學(xué)分?jǐn)?shù)基本都在297-299之間(滿分300分),少有300分的同學(xué)。本來想改來著,轉(zhuǎn)念一想都滿分也不太好,有點(diǎn)誤差也好,可能這部分不會改了,感興趣的可以自己改改看。

ps: 本校的可以直接搭好拿來用就可以了,其他同學(xué)如有類似需求,這個系統(tǒng)是某公司開發(fā)的,好多學(xué)校都在用,folk一份改改應(yīng)該也沒問題。 戳到github吧,歡迎 star、folk。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容