學校教務系統的課程表爬取


課程作業需要實現一個課程表,我負責完成學校的教務系統中課程表的導入工作。

需要解決兩個問題,第一個是教務系統訪問課程表所在url時,會被告知需要先加載某框架,這讓我很困擾,不知道如何用urlopen去解決這個問題;第二個問題是,不同的課程對應的課時是不一樣的,意味着顯示的時候rowspan值是不一樣的,需要重新進行解析。

第一個問題采用selenium庫,然后使用Chrome的headless模式就可以解決模擬登陸並獲取課程表的html。
這里面課程表所在頁面的url不是固定的,而是存在於MenuFrame的一段js代碼中,因此采用js2xml對js代碼格式化,然后使用xpath提取其中的url。
代碼如下:

def login(login_driver, username, password):
    login_driver.get('http://yjxt.bupt.edu.cn')
    username = login_driver.find_element(By.ID, 'username')
    username.send_keys(username)

    password = login_driver.find_element(By.ID, 'password')
    password.send_keys(password)

    button = login_driver.find_element_by_class_name('btn-lg')
    button.click()


def get_payload(get_payload_driver):
    # 課程表所在頁面的url不是固定的,需要從js代碼中提取
    get_payload_driver.switch_to.frame('MenuFrame')
    source = get_payload_driver.page_source

    soup = BeautifulSoup(source, 'html.parser')
    script = soup.select('body form script')[1].string

    # 使用js2xml格式化之后再使用xpath提取js代碼中附加的url
    script_text = js2xml.parse(script, debug=False)

    for x in script_text.xpath("//object/property[@name = 'url']/string/text()"):
        if x[:21] == 'Course/StuCourseQuery':
            return x


def get_course_html(get_course_html_driver, payload):
    get_course_html_driver.get('http://yjxt.bupt.edu.cn/Gstudent/' + payload)
    return get_course_html_driver.page_source

在獲取課程表頁面的html之后就需要去解析課程表,課程表中每個課程占據的單元格是不定的,比如數學課占據了周一上午的第一節和第二節課,那么在遍歷的過程中是無法遍歷到周一上午第二節課這個單元格的,實際獲取的單元格是周二上午第二節課,因此需要獲得下一個單元格的實際位置用於同步,這里維護了一個二維數組用於模擬課程表,在遍歷的過程中對其染色,比如遍歷到了周一上午第一節課,會同時將第二節課也染色,這樣就可以根據next_pic()函數獲取實際的位置。代碼如下:

def next_pic(pic, x, y):
    for i in range(x, 11):
        if i == x:
            for j in range(y, 9):
                if pic[i][j] == 0 and j != y:
                    return i, j
        else:
            for j in range(9):
                if pic[i][j] == 0:
                    return i, j


def analysis_html(html):
    # 解析html

    # 獲取table
    soup = BeautifulSoup(html, 'html.parser')
    table = soup.find(id='contentParent_dgData')

    # 解析table
    pic = [[0 for i in range(9)] for i in range(11)]
    row = 0
    column = 0

    for x in table.find_all('td'):
        if x.string != '\n':
            try:
                rowspan = int(x['rowspan'])
            except AttributeError as e:
                rowspan = 1

            for i in range(rowspan):
                pic[row + i][column] = 1

            if x.string.strip().encode('utf-8') in EnumA:
                row, column = next_pic(row, column)
                continue
            else:
                print(x.string.strip().encode('gbk'), '周'.decode('utf-8').encode('gbk'),
                      column, row + 1, '-', row + rowspan)
        else:
            row, column = next_pic(row, column)

完整的代碼見github


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM