用selenium制作爬虫爬取教务课程信息
https://github.com/plutojia/Crawler-with-checkcode-recognition-
前段时间在选课,而我们的教务系统又十分蛋疼。先是在选课时不停崩溃,进不去,选课结束要打印选课单时又因为它自己系统太老而不支持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)