1. 程式人生 > >用selenium製作爬蟲爬取教務課程資訊

用selenium製作爬蟲爬取教務課程資訊

前段時間在選課,而我們的教務系統又十分蛋疼。先是在選課時不停崩潰,進不去,選課結束要列印選課單時又因為它自己系統太老而不支援64位瀏覽器列印課表。。。沒有辦法我就寫了一個爬取教務課程資訊並將其儲存在MongoDB中的程式,這個程式稍微改改就可以變成搶課指令碼了。內容有:

  • 使用selenium驅動chrome瀏覽器
  • 用pytesseract識別驗證碼
  • MongoDB儲存

首先選課系統長這個樣子:

需要做的是通過指令碼輸入使用者名稱和密碼,並識別驗證碼登陸教務系統,跳轉到選課頁面,獲取選課資訊,最後將資訊儲存於MongoDB中。

開啟開發者工具,定位登陸表單各元素:

依次獲取元素填寫相應欄位,最後模擬點選登陸即可,程式碼如下:


def login():
    browser.get('http://gsmis.graduate.buaa.edu.cn/gsmis/main.do')
    browser.maximize_window()
    input_id=browser.find_element_by_xpath('//input[@name="id"]')
    input_password =browser.find_element_by_xpath('//input[@name="password"]')
    input_checkcode=browser.find_element_by_xpath('//input[@name="checkcode"]')
    img_checkcode=browser.find_element_by_xpath('//img[@src="/gsmis/Image.do"]')

    location = img_checkcode.location
    size = img_checkcode.size
    browser.save_screenshot('checkcode.png')
    checkcode=getCheckcode('checkcode.png',location,size)

    input_id.send_keys(data['id'])
    input_password.send_keys(data['password'])
    input_checkcode.send_keys(checkcode)

    lg_button=browser.find_element_by_xpath('//img[@onclick="document.forms[0].submit()"]')

    time.sleep(1)
    lg_button.click()

其中有識別驗證碼的部分,識別函式採取的是將驗證碼截圖,儲存,交給pytesseract識別的方法,為了提高識別準確度,對驗證碼圖片進行了二值化處理,並在OCR識別後對一些容易混淆為字母的數字進行了糾正,程式碼如下:

def initTable(threshold=140):           # 二值化函式
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)

    return table

def getCheckcode(savepath,location,size):
    rep = {'O': '0',  # replace list
           'I': '1', 'L': '1',
           'Z': '2',
           'S': '8'
           };
    im = Image.open(savepath)
    location['x']=825
    location['y']=495
    left = location['x']
    top = location['y']
    right = location['x'] + size['width']
    bottom = location['y'] + size['height']
    im = im.crop((left, top, right, bottom))
    im.save(savepath)
    im = im.convert('L')
    binaryImage = im.point(initTable(), '1')
    # binaryImage.show()
    checkcode = pytesseract.image_to_string(binaryImage, config='-psm 7')
    for r in rep:
        checkcode = checkcode.replace(r, rep[r])
    print(checkcode)
    return checkcode

這樣就登陸進入了教務系統主頁,還需要開啟選課頁面。這裡注意frame的切換,在父frame裡無法定位子frame的元素,所以要根據情況switch到子frame:

def navigate():
    time.sleep(1)
    browser.get("http://gsmis.graduate.buaa.edu.cn/gsmis/toModule.do?prefix=/py&page=/pySelectCourses.do?do=xsXuanKe")
    browser.switch_to.frame('frmme')
    browser.switch_to.frame('leftFrame')
    xuanke=browser.find_element_by_xpath('//a[@href="/gsmis/py/pySelectCourses.do?do=xuanBiXiuKe"]')
    xuanke.click()
    browser.switch_to.parent_frame()
    browser.switch_to.frame('mainFrame')

現在到了這一步,獲取課程資訊並儲存即可:

def prase():
    lessons=browser.find_elements_by_class_name("tablefont2")
    for lesson in lessons:
        infos=lesson.find_elements_by_xpath("./td")
        is_selected = infos[0].find_element_by_xpath("./input").is_selected()
        if(is_selected):
            info={
                'when&where':infos[1].text,
                'classification': infos[3].text,
                'name': infos[4].text,
                'teacher': infos[10].text,
                'remian': infos[12].text,
            }
            yield(info)


MONGO_URL = 'localhost'
MONGO_DB = 'jiaowu'
MONGO_COLLECTION = 'Curriculum'
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]
def save_to_mongo(result):
    """
    儲存至MongoDB
    :param result: 結果
    """
    try:
        if db[MONGO_COLLECTION].insert(result):
            print('儲存到MongoDB成功')
    except Exception:
        print('儲存到MongoDB失敗')

執行結果如下:

完整程式碼:

import pytesseract
import requests
from PIL import Image
import os
from selenium import webdriver
import time
from selenium.webdriver.support.wait import WebDriverWait
import pymongo

data={
    'id':'xxxxxxxx',
    'password':'xxxxxxxxx',
    'checkcode':''
}
browser = webdriver.Chrome()
wait = WebDriverWait(browser, 10)

def initTable(threshold=140):           # 二值化函式
    table = []
    for i in range(256):
        if i < threshold:
            table.append(0)
        else:
            table.append(1)

    return table

def getCheckcode(savepath,location,size):
    rep = {'O': '0',  # replace list
           'I': '1', 'L': '1',
           'Z': '2',
           'S': '8'
           };
    im = Image.open(savepath)
    location['x']=825
    location['y']=495
    left = location['x']
    top = location['y']
    right = location['x'] + size['width']
    bottom = location['y'] + size['height']
    im = im.crop((left, top, right, bottom))
    im.save(savepath)
    im = im.convert('L')
    binaryImage = im.point(initTable(), '1')
    # binaryImage.show()
    checkcode = pytesseract.image_to_string(binaryImage, config='-psm 7')
    for r in rep:
        checkcode = checkcode.replace(r, rep[r])
    print(checkcode)
    return checkcode

def login():
    browser.get('http://gsmis.graduate.buaa.edu.cn/gsmis/main.do')
    browser.maximize_window()
    input_id=browser.find_element_by_xpath('//input[@name="id"]')
    input_password =browser.find_element_by_xpath('//input[@name="password"]')
    input_checkcode=browser.find_element_by_xpath('//input[@name="checkcode"]')
    img_checkcode=browser.find_element_by_xpath('//img[@src="/gsmis/Image.do"]')

    location = img_checkcode.location
    size = img_checkcode.size
    browser.save_screenshot('checkcode.png')
    checkcode=getCheckcode('checkcode.png',location,size)

    input_id.send_keys(data['id'])
    input_password.send_keys(data['password'])
    input_checkcode.send_keys(checkcode)

    lg_button=browser.find_element_by_xpath('//img[@onclick="document.forms[0].submit()"]')

    time.sleep(1)
    lg_button.click()

def navigate():
    time.sleep(1)
    browser.get("http://gsmis.graduate.buaa.edu.cn/gsmis/toModule.do?prefix=/py&page=/pySelectCourses.do?do=xsXuanKe")
    browser.switch_to.frame('frmme')
    browser.switch_to.frame('leftFrame')
    xuanke=browser.find_element_by_xpath('//a[@href="/gsmis/py/pySelectCourses.do?do=xuanBiXiuKe"]')
    xuanke.click()
    browser.switch_to.parent_frame()
    browser.switch_to.frame('mainFrame')

def prase():
    lessons=browser.find_elements_by_class_name("tablefont2")
    for lesson in lessons:
        infos=lesson.find_elements_by_xpath("./td")
        is_selected = infos[0].find_element_by_xpath("./input").is_selected()
        if(is_selected):
            info={
                'when&where':infos[1].text,
                'classification': infos[3].text,
                'name': infos[4].text,
                'teacher': infos[10].text,
                'remian': infos[12].text,
            }
            yield(info)


MONGO_URL = 'localhost'
MONGO_DB = 'jiaowu'
MONGO_COLLECTION = 'Curriculum'
client = pymongo.MongoClient(MONGO_URL)
db = client[MONGO_DB]
def save_to_mongo(result):
    """
    儲存至MongoDB
    :param result: 結果
    """
    try:
        if db[MONGO_COLLECTION].insert(result):
            print('儲存到MongoDB成功')
    except Exception:
        print('儲存到MongoDB失敗')

login()
navigate()
for res in prase():
    print(res)
    save_to_mongo(res)