1. 程式人生 > >用 Python 實現武科大教務處自動搶課

用 Python 實現武科大教務處自動搶課

kit overflow 簡單的 pos request 直接 sts itl head

首先分析網頁,找到教務處登錄的驗證碼
技術分享圖片

然後用 Python 直接把驗證碼下載到本地(整個程序通過 requests 庫實現):

def GetRandCode():
    url = r‘http://jwxt.wust.edu.cn/whkjdx/verifycode.servlet‘
    ans = foo.get(url)
    with open(‘randcode.jpg‘, ‘wb‘) as file:
        file.write(ans.content)

找到驗證碼之後繼續找到登錄的api,我們可以發現網頁發出了一個 post 請求,還有相關參數:
技術分享圖片

接著要實現登錄就非常簡單了,我先簡單寫了個登錄的實現:

foo = foo = requests.session()
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
}

def Login(username, password, randcode):
    url = r‘http://jwxt.wust.edu.cn/whkjdx/Logon.do?method=logon‘
    information = {‘USERNAME‘
: username, ‘PASSWORD‘: password, ‘RANDOMCODE‘: randcode} ans = foo.post(url, data = information, headers = headers) ans.raise_for_status() ans.encoding = ans.apparent_encoding if ans.text.find(r‘http://jwxt.wust.edu.cn/whkjdx/framework/main.jsp‘) != -1: return True else: return
False

測試了一下發現是可以正常登錄的,緊接著就要做獲取選課列表了,方法同上。
我發現本學期的獲取選課列表的地址是 http://jwxt.wust.edu.cn/whkjdx/xkglAction.do?method=toFindxskxkclb&xnxq01id=2017-2018-2&zzdxklbname=1&type=1&jx02kczid=null 很明顯參數 xnxq01id 應該就是學期號了,規則也很容易發現。然後我就直接用Python實現了一下,然後發現網頁會返回沒有訪問權限的消息。回過頭分析登錄過程,發現還有一個 SSO(點對點登錄)的 API,然後試了一下新的登錄函數:

def Login(username, password, randcode):
    url = r‘http://jwxt.wust.edu.cn/whkjdx/Logon.do?method=logon‘
    SSOurl = r‘http://jwxt.wust.edu.cn/whkjdx/Logon.do?method=logonBySSO‘
    information = {‘USERNAME‘: username, ‘PASSWORD‘: password, ‘RANDOMCODE‘: randcode}
    ans = foo.post(url, data = information, headers = headers)
    ans.raise_for_status()
    ans.encoding = ans.apparent_encoding
    ans2 = foo.post(SSOurl, headers)
    ans2.raise_for_status()
    if ans.text.find(r‘http://jwxt.wust.edu.cn/whkjdx/framework/main.jsp‘) != -1:
        return True
    else:
        return False

通過新的登錄函數可以正常獲取公選課選課列表。具體實現如下:

def GetCoursesList():
    url = r‘http://jwxt.wust.edu.cn/whkjdx/xkglAction.do?method=toFindxskxkclb&xnxq01id=2017-2018-2&zzdxklbname=1&type=1&jx02kczid=null‘
    ans = foo.get(url, headers = headers)
    ans.raise_for_status()
    ans.encoding = ans.apparent_encoding
    CoursesList = re.findall(r‘<td height="23"  style="text-overflow:ellipsis; white-space:nowrap; overflow:hidden;" width="\d+" title=".*"‘, ans.text)
    XKLJList = re.findall("javascript:vJsMod\(\‘.*\‘", ans.text)
    keyname = [‘kcmc‘, ‘kkdw‘, ‘zyfx‘, ‘xf‘, ‘yxrs‘, ‘yl‘, ‘skjs‘, ‘skzc‘, ‘sksj‘, ‘skdd‘, ‘kcsx‘, ‘kcxz‘, ‘fzm‘, ‘xbyq‘]
    result = []
    item = {}
    bar = 0
    index = 0
    for i in CoursesList:
        Left = i.find(r‘title="‘)
        Right = i[Left + 7:].find(r‘"‘)
        text = i[Left + 7:Left + Right + 7]
        #print(i)
        #print(text)
        item[keyname[bar]] = text
        bar = bar + 1
        if (bar == 14):
            Left = XKLJList[index].find("‘")
            Right = XKLJList[index][Left + 1:].find("‘")
            text = XKLJList[index][Left + 1:Left + Right + 1]
            item[‘xklj‘] = text
            index = index + 1

            result.append(item)
            item = {}
            bar = 0
    return result

其中正則表達式匹配所有網頁列表中的信息,每 14 項是一個課程的全部信息,具體信息對應哪些,可以看列表的表頭,我用字典來保存這些課程的信息,然後存到一個列表裏,每個信息的拼音簡寫就是字典中對應的鍵的名稱,然後又有一個 xklj 用來保存選課時需要通過 get 訪問的鏈接,這樣實現選課就非常簡單了,只需要對這個鏈接發送 get 請求即可:

def ChoseCourseByLink(link):
    url = ‘http://jwxt.wust.edu.cn‘ + link
    ans = foo.get(url, headers = headers)
    ans.raise_for_status()
    ans.encoding = ans.apparent_encoding
    return ans.text

然後用同樣的辦法構造學分制選課的列表:

def GetCoursesList2():
    url = r‘http://jwxt.wust.edu.cn/whkjdx/xkglAction.do?method=toFindxskxkclb&xnxq01id=2017-2018-2&zzdxklbname=6&type=1&jx02kczid=null‘
    ans = foo.get(url, headers = headers)
    ans.raise_for_status()
    ans.encoding = ans.apparent_encoding
    CoursesList = re.findall(r‘<td height="23"  style="text-overflow:ellipsis; white-space:nowrap; overflow:hidden;" width="\d+" title=".*"‘, ans.text)
    XKLJList = re.findall("javascript:vJsMod\(\‘.*\‘", ans.text)
    keyname = [‘kcmc‘, ‘kkdw‘, ‘zyfx‘, ‘xf‘, ‘yxrs‘, ‘yl‘, ‘skjs‘, ‘skzc‘, ‘sksj‘, ‘skdd‘, ‘kcsx‘, ‘kcxz‘, ‘fzm‘, ‘xbyq‘]
    result = []
    item = {}
    bar = 0
    index = 0
    for i in CoursesList:
        Left = i.find(r‘title="‘)
        Right = i[Left + 7:].find(r‘"‘)
        text = i[Left + 7:Left + Right + 7]
        #print(i)
        #print(text)
        item[keyname[bar]] = text
        bar = bar + 1
        if (bar == 14):
            Left = XKLJList[index].find("‘")
            Right = XKLJList[index][Left + 1:].find("‘")
            text = XKLJList[index][Left + 1:Left + Right + 1]
            item[‘xklj‘] = text
            index = index + 1

            result.append(item)
            item = {}
            bar = 0
    return result

這樣一個簡單的搶課庫就實現了,搶課的時候只需要調用相關的接口就行了,最終全部代碼在我的 Github 上:https://github.com/Rugel/wustjwxt

用 Python 實現武科大教務處自動搶課