用Python查詢成績|(二)模擬登錄教務(wù)網(wǎng)并獲取成績

前言

av8d大家好鴿了幾個(gè)月的我又回來了疆前!

在上一篇用Python查詢成績|(一)網(wǎng)絡(luò)爬蟲基礎(chǔ)知識中我大概的講了一下網(wǎng)絡(luò)爬蟲的基礎(chǔ)知識,這一篇就有干貨了啊禽翼,直接開始模擬登錄教務(wù)網(wǎng)捍壤。

本篇內(nèi)容

  • 1续誉, 用 Python 模擬登錄教務(wù)網(wǎng)
  • 2哲银, 獲取成績

以下代碼均可以在我的 Github 上找到:

https://github.com/DuChuan19/NkemisScoreSpider

免責(zé)聲明:本文僅供學(xué)習(xí)交流扛吞,如出現(xiàn)任何法律問題本人概不負(fù)責(zé)!

用 Python 模擬登錄教務(wù)網(wǎng)

整體思路

1荆责,向登錄界面發(fā)送登錄請求滥比,POST 一系列參數(shù),包括賬號做院、密碼等盲泛,獲得響應(yīng),提取一些關(guān)鍵參數(shù)

2山憨,得到參數(shù)重新發(fā)送登錄請求查乒,POST 參數(shù)之后即可登錄

第一次向登錄界面發(fā)送請求

第一次向登陸頁面發(fā)送請求弥喉,是為了看看需要 POST 哪些參數(shù)郁竟,光提交賬號密碼是肯定不行的。

1.png

這里可以看除了賬號密碼還有另外的四個(gè)參數(shù)由境,分別是__VIEWSTATE 棚亩、__VIEWSTATEGENERATORImageButton1.x蓖议、ImageButton1.y,前兩個(gè)經(jīng)過分析可以在登錄頁面找到

2.png

我們可以通過 requests 的 get 方法得到

后面兩個(gè)應(yīng)該是登錄按鈕的位置

3.png

然后可以通過以下代碼來得到需要的參數(shù)讥蟆,賬號密碼可以手動輸入

def post_data(self):
    """
        獲取用戶登錄時(shí)需要提交的數(shù)據(jù)
        :return: data
        """
    try:
        html = requests.get(self.SYSTEMLOGIN_URL, headers=self.random_header())
        bsObj = BeautifulSoup(html.text, 'lxml')
        __VIEWSTATE = bsObj.find('input').attrs['value']
        __VIEWSTATEGENERATOR = bsObj.find('input', id='__VIEWSTATEGENERATOR').attrs['value']
        data = {
            "__VIEWSTATE": __VIEWSTATE,
            "__EVENTVALIDATION": __VIEWSTATEGENERATOR,
            "txtUserID": self.textUserID,
            "txtPasswd": self.textPasswd,
            "ImageButton1.x": 1,
            "ImageButton1.y": 1
        }
        return data

第二次向登錄界面發(fā)送請求

這次請求需要包含以上獲得的參數(shù)勒虾,不然沒法得到正確的響應(yīng)

直接來看代碼:

session = requests.session()
session.post(self.SYSTEMLOGIN_URL, data=self.post_data())

關(guān)于 session 的詳細(xì)說明以及用法,可以訪問官方文檔進(jìn)行查看

這里我大概的說一下

requests 庫的 session 對象能夠幫我們跨請求保持某些參數(shù)瘸彤,也會在同一個(gè) session 實(shí)例發(fā)出的所有請求之間保持cookies

所以我們發(fā)送了帶有登錄參數(shù)的數(shù)據(jù)修然,如果參數(shù)正確,就能登錄成功了

4.png

獲取成績

成功登錄教務(wù)網(wǎng)之后质况,接下來便是獲取成績了

我們需要獲取的數(shù)據(jù)只有兩個(gè)愕宋,課程標(biāo)題以及對應(yīng)的總評成績

這里有兩種方法,一種是通過正則表達(dá)式來獲取结榄,另一種是用 pandas 庫

用正則表達(dá)式來獲取成績

5.png

可以看到中贝,課程名稱和總評成績都包含在 tr 標(biāo)簽下

為了方便看,我把課程名稱和總評成績分開寫

# 課程標(biāo)題
title_pattern = re.compile('<tr align="center">.*?<td align="left">.*?<a.*?>(.*?)</a>', re.S)
title_items = re.findall(title_pattern, res.text)

# 每科對應(yīng)總成績
score_pattern = re.compile('<tr align="center">.*?<td align="left">.*?<a.*?>.*?</a>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>(.*?)<td>',re.S)
score_items = re.findall(score_pattern, res.text)

下面是登錄和獲取成績的完整代碼:

def get_score(self):
        """
        登錄教務(wù)網(wǎng)并且獲取課程標(biāo)題以及對應(yīng)的成績
        :return:
        """
    # Login
    session = requests.session()
    session.post(self.SYSTEMLOGIN_URL, data=self.post_data())

    # Get score
    res = session.get(url=self.SCOREQUERY_URL)

    # 課程標(biāo)題
    title_pattern = re.compile('<tr align="center">.*?<td align="left">.*?<a.*?>(.*?)</a>', re.S)
    title_items = re.findall(title_pattern, res.text)

    # 每科對應(yīng)總成績
    score_pattern = re.compile('<tr align="center">.*?<td align="left">.*?<a.*?>.*?</a>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>(.*?)<td>',re.S)
    score_items = re.findall(score_pattern, res.text)

    # 將數(shù)據(jù)保存為字典格式
    for title, score in zip(title_items, score_items):
        self.ITEMS.append({
            'title': title.replace('\r', '').replace('\t', '').replace('\n', ''),
            'score': score.replace('</td>', '')
        })

我們將獲取到的數(shù)據(jù)保存為字典格式臼朗,以便后面入庫

運(yùn)行一下邻寿,成功得到了課程名稱和總評成績(學(xué)渣一枚,成績太差了视哑,見笑)

6.png

下面是完整代碼:

# -*-coding:utf8-*-
import re
import random
import pandas
import pymysql
import requests
from bs4 import BeautifulSoup


class Nkemis_helper(object):

    def __init__(self, textUserID, textPasswd):
        """
        Nkemis Helper
        :param textUserID: 學(xué)號
        :param textPasswd: 密碼
        """

        self.textUserID = textUserID
        self.textPasswd = textPasswd
        self.SYSTEMLOGIN_URL = 'http://222.30.63.15/NKEMIS/SystemLogin.aspx'
        self.SCOREQUERY_URL = "http://222.30.63.15/nkemis/Student/ScoreQuery.aspx"

        self.ITEMS = []  # 存放課程標(biāo)題以及對應(yīng)的成績

    def random_header(self):
        """
        隨機(jī)選取一個(gè) User-Agent
        :return: random header
        """
        USERAGENT_LIST = [
            "Mozilla/5.0(Macintosh;IntelMacOSX10.6;rv:2.0.1)Gecko/20100101Firefox/4.0.1",
            "Mozilla/4.0(compatible;MSIE6.0;WindowsNT5.1)",
            "Opera/9.80(WindowsNT6.1;U;en)Presto/2.8.131Version/11.11",
            "Mozilla/5.0(Macintosh;IntelMacOSX10_7_0)AppleWebKit/535.11(KHTML,likeGecko)Chrome/17.0.963.56Safari/535.11",
            "Mozilla/4.0(compatible;MSIE7.0;WindowsNT5.1)",
            "Mozilla/4.0(compatible;MSIE7.0;WindowsNT5.1;Trident/4.0;SE2.XMetaSr1.0;SE2.XMetaSr1.0;.NETCLR2.0.50727;SE2.XMetaSr1.0)",
        ]
        return {"User-Agent": random.choice(USERAGENT_LIST)}

    def post_data(self):
        """
        獲取用戶登錄時(shí)需要提交的數(shù)據(jù)
        :return:
        """

        try:
            html = requests.get(self.SYSTEMLOGIN_URL, headers=self.random_header())
            bsObj = BeautifulSoup(html.text, 'lxml')
            __VIEWSTATE = bsObj.find('input').attrs['value']
            __VIEWSTATEGENERATOR = bsObj.find('input', id='__VIEWSTATEGENERATOR').attrs['value']
            data = {
                "__VIEWSTATE": __VIEWSTATE,
                "__EVENTVALIDATION": __VIEWSTATEGENERATOR,
                "txtUserID": self.textUserID,
                "txtPasswd": self.textPasswd,
                "ImageButton1.x": 1,
                "ImageButton1.y": 1
            }
            return data
        except:
            print('網(wǎng)絡(luò)未連接, 請查看網(wǎng)絡(luò)')

    def get_score(self):
        """
        登錄教務(wù)網(wǎng)并且獲取課程標(biāo)題以及對應(yīng)的成績
        :return:
        """

        # Login
        session = requests.session()
        session.post(self.SYSTEMLOGIN_URL, data=self.post_data())

        # Get score
        res = session.get(url=self.SCOREQUERY_URL)

        # 課程標(biāo)題
        title_pattern = re.compile('<tr align="center">.*?<td align="left">.*?<a.*?>(.*?)</a>', re.S)
        title_items = re.findall(title_pattern, res.text)

        # 每科對應(yīng)總成績
        score_pattern = re.compile('<tr align="center">.*?<td align="left">.*?<a.*?>.*?</a>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>.*?<td>(.*?)<td>',re.S)
        score_items = re.findall(score_pattern, res.text)

        # 將數(shù)據(jù)保存為字典格式
        for title, score in zip(title_items, score_items):
            self.ITEMS.append({
                'title': title.replace('\r', '').replace('\t', '').replace('\n', ''),
                'score': score.replace('</td>', '')
            })
        print(self.ITEMS)

    def save_to_mysql(self):
        # connect mysql
        db = pymysql.connect("localhost", "root", "toor", "db_nkemis")
        cursor = db.cursor()

        # 以學(xué)號作為表名創(chuàng)建表
        try:
            CREATE_TABLE_SQL = "CREATE TABLE student_%s (title varchar(255), score varchar(255))" % self.textUserID
            cursor.execute(CREATE_TABLE_SQL)
            db.commit()
        except:
            db.rollback()

        # 將學(xué)生成績存進(jìn)數(shù)據(jù)庫
        for item in self.ITEMS:
            INSERT_SQL = "INSERT INTO student_%s (title, score) VALUES ('%s', '%s')" % (self.textUserID, item['title'], item['score'])
            cursor.execute(INSERT_SQL)
            db.commit()

        db.close()


if __name__ == '__main__':
    textUserID = input("學(xué)號: ")
    textPasswd = input("密碼: ")

    helper = Nkemis_helper(textUserID, textPasswd)
    helper.get_score()
    helper.save_to_mysql()

爬取數(shù)據(jù)下來之后入庫:

7.jpg

用 pandas 來獲取成績

7.png

我們可以看到绣否,無論是課程名稱還是成績,都是包含在一個(gè) table 里黎炉,用 pandas 就可以很方便快速的提取這個(gè) table

8.png

下面是完整代碼:

# -*-coding:utf8-*-
import re
import random
import pandas
import pymysql
import requests
from bs4 import BeautifulSoup


html = requests.get('http://222.30.63.15/NKEMIS/SystemLogin.aspx')
bsObj = BeautifulSoup(html.text, 'lxml')
__VIEWSTATE = bsObj.find('input').attrs['value']
__VIEWSTATEGENERATOR = bsObj.find('input', id='__VIEWSTATEGENERATOR').attrs['value']
data = {
    "__VIEWSTATE": __VIEWSTATE,
    "__EVENTVALIDATION": __VIEWSTATEGENERATOR,
    "txtUserID": 學(xué)號,
    "txtPasswd": 密碼,
    "ImageButton1.x": 1,
    "ImageButton1.y": 1
}

session = requests.session()
session.post('http://222.30.63.15/NKEMIS/SystemLogin.aspx', data=data)
res = session.get(url='http://222.30.63.15/nkemis/Student/ScoreQuery.aspx')
bsObj = BeautifulSoup(res.text, 'lxml')
dfs = pandas.read_html(bsObj.select_one('table.dgrdglobal').prettify())
df = pandas.DataFrame(dfs[0]).drop([1,2,3,4,7,9,8,12], axis=1)

總結(jié)

這人太懶了枝秤,沒有寫總結(jié)。

偷偷BB一句慷嗜,這個(gè)爬蟲拿去參加了計(jì)算機(jī)系的多媒體大賽淀弹,混到了個(gè)獎狀 :)

(叉會兒腰)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市庆械,隨后出現(xiàn)的幾起案子薇溃,更是在濱河造成了極大的恐慌,老刑警劉巖缭乘,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件沐序,死亡現(xiàn)場離奇詭異,居然都是意外死亡堕绩,警方通過查閱死者的電腦和手機(jī)策幼,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來奴紧,“玉大人特姐,你說我怎么就攤上這事∈虻” “怎么了唐含?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵浅浮,是天一觀的道長。 經(jīng)常有香客問我捷枯,道長滚秩,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任淮捆,我火速辦了婚禮郁油,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘攀痊。我一直安慰自己已艰,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布蚕苇。 她就那樣靜靜地躺著哩掺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天闰蛔,我揣著相機(jī)與錄音冗恨,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播誊稚,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼罗心!你這毒婦竟也來了里伯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤渤闷,失蹤者是張志新(化名)和其女友劉穎疾瓮,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體飒箭,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡狼电,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弦蹂。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肩碟。...
    茶點(diǎn)故事閱讀 38,622評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖凸椿,靈堂內(nèi)的尸體忽然破棺而出削祈,到底是詐尸還是另有隱情,我是刑警寧澤削饵,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布岩瘦,位于F島的核電站,受9級特大地震影響窿撬,放射性物質(zhì)發(fā)生泄漏启昧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一劈伴、第九天 我趴在偏房一處隱蔽的房頂上張望密末。 院中可真熱鬧,春花似錦跛璧、人聲如沸严里。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刹碾。三九已至,卻和暖如春座柱,著一層夾襖步出監(jiān)牢的瞬間迷帜,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工色洞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留戏锹,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓火诸,卻偏偏與公主長得像锦针,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子置蜀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 點(diǎn)擊查看原文 Web SDK 開發(fā)手冊 SDK 概述 網(wǎng)易云信 SDK 為 Web 應(yīng)用提供一個(gè)完善的 IM 系統(tǒng)...
    layjoy閱讀 13,700評論 0 15
  • 最近學(xué)校開始選課奈搜,但是如果選課時(shí)間與自己的事情沖突,這時(shí)候就可以使用Python腳本自助搶課盯荤,搶課的第一步即是模擬...
    派派森森閱讀 2,522評論 1 9
  • 親子日記第168篇 周末真好媚污,可以睡到自然醒,今天起床的時(shí)候已經(jīng)9點(diǎn)多了廷雅。我家的小鬧鐘怎么沒響呢耗美。我往兒子屋里...
    子浩媽媽閱讀 317評論 0 3
  • 手里握著的 心里念念不忘的 記憶深處不敢遺忘的 是真愛 是欲望 是思念 我是個(gè)俗人 是落在石頭縫隙里的草籽 苦熬過...
    吳有_4e39閱讀 97評論 0 5
  • 小時(shí)候守著收音機(jī)聽評書的日子,記憶猶新航缀。劉蘭芳講的《岳飛傳》,《楊家將》商架,袁闊成講的《三國演義》,都是兒時(shí)聽廣播時(shí)...
    似曾相識a閱讀 439評論 5 9