这是一篇介绍如何通过Python实现模拟登陆学校教务系统并爬取成绩相关信息(学期,课程名,总成绩,课程性质,学分)然后绘制成绩分布折线图最后导入MySQL数据库中的文章
为了利用充分利用selenium的功能和成功爬取数据,需要有前置的html、css、简单爬虫的相关知识
说明:我学校的成绩查询页面是通过加载js框架进而动态实时加载显示表格及数据的,如果仅仅是用一般的爬虫方法直接爬取页面信息,是不能成功的,因为那样是直接获取网页源码,其中并没有成绩数据。当然,采用某些爬虫方法肯定也能实现爬取js动态网页,但是我为了简单起见,直接用了selenium模拟登陆系统然后爬取信息。
一、导入主要模块
from bs4 import BeautifulSoup
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.keys import Keys
import matplotlib.pyplot as plt
import time
import pymysql
二、利用selenium模拟登陆教务系统
1.首先给出系统登陆页面url和成绩查询页面url(方便登陆成功后直接跳转,省去了鼠标点击相关链接的操作)
# 给出所需的url
url_login_page = ("你学校的教务系统登录页面url")
url_cjcx=("成绩查询页面url")
2.打开系统登录页面
# 启动Chorme驱动,开始模拟(不能用静默模式启动)
option = webdriver.ChromeOptions()
# 不加载图片,提高访问速度
option.add_argument('blink-settings=imagesEnabled=false')
driver = webdriver.Chrome(chrome_options=option)
driver.maximize_window()
print("正在访问......")
driver.get(url_login_page)
3.模拟输入账号密码并点击登陆按钮
这里需要你自己用F12去查看自己学校系统登陆页面的网页元素然后找到账号密码输入框、登录按钮的元素名称(这里我通过find_element_by_id找到了所需的输入框及按钮)
# 自动输入账号密码
driver.find_element_by_id("username").send_keys("你的学号")
driver.find_element_by_id("password").send_keys("你的密码")
# 找到并点击登录按钮,实现登录
login_button = driver.find_element_by_id("login_submit")
actions = ActionChains(driver)
actions.key_down(Keys.CONTROL).click(login_button).key_up(Keys.CONTROL).perform()
三、爬取成绩信息
1.在新页面打开成绩查询页面
# 打开新的地址
driver.switch_to.window(driver.window_handles[-1])
driver.get(url_cjcx)
2.等待成绩查询页面加载完毕
我学校的查询页面与学校数据库对接较缓慢,所以我设置了10s等待时间,否则页面加载不出来会报错
# 等待页面加载完毕
time.sleep(10)
3.找到“每页显示50条数据”的按钮并点击
这里我想点击“每页显示50条数据”按钮是因为这样可以直接爬取所有数据而不需要点击“下一页”按钮。同样地,这里根据个人需要调整参数即可
# 找到每页显示数目选择框并点击"50"
driver.find_element_by_class_name("bh-pull-right.jqx-widget.jqx-dropdownlist-state-normal.jqx-rc-all.jqx-fill-state-normal").click()
time.sleep(0.5)
driver.find_element_by_xpath("//span[text()='50']").click()
# 等待页面加载完毕
time.sleep(1)
4.爬取成绩查询页面的信息
这里采用的方法是先用driver.page_source+BeautifulSoup的方法获取当前页面的源码然后采用一般的爬虫方法获取相关信息
# 准备爬取成绩查询页面的信息
data = driver.page_source
soup = BeautifulSoup(data, 'lxml')
trs = soup.find_all("tr")
total_container = []
for tr in trs:
row_container = []
for span in tr:
row_container.append(span.string)
total_container.append(row_container)
# 初始化score subjects列表
score = []
subjects = []
# 输出最近两学期成绩数据
print("近两学期所有科目成绩如下:")
subject_num = int(len(total_container)/2)
for i in range(1,subject_num+1):
print(total_container[i-1][1], total_container[i-1][2], total_container[i-1][6], total_container[i-1][9], total_container[i-1][11])
subjects.append(total_container[i-1][2])
score.append(total_container[i-1][6])
print("\n原始成绩:",score,"\n")
# 规范化成绩
for i in range(1,subject_num+1):
if score[i-1] == '优秀' or score[i-1] =='621':
score[i-1] = 95
elif score[i-1] == '良好':
score[i-1] = 85
elif score[i-1] == '通过':
score[i-1] = 75
elif score[i-1] == None:
score[i-1] = 98
else:
score[i-1] = int(score[i-1])
print("科目:",subjects,"\n")
print("规范化后的成绩:",score)
结果:
四、绘制成绩分布统计图
我们采用matplotlib.pyplot画图
# 绘图
print("\n正在绘制成绩分布折线图...")
x = range(subject_num)
# plt.xticks(x,subjects) # 可以设置坐标字
plt.plot(x, score)
plt.xlabel("Subject(The xth)") #X轴标签
plt.ylabel("Score") #Y轴标签
plt.title('Score Distribution Chart')
plt.show()
结果:
五、将数据导入MySQL
# 写入MySQL
print("\n正在连接MySQL服务\n...")
# 创建与测试数据库的连接
conn = pymysql.connect(host='localhost',user="root",password="你的密码",database="score_db")
# 输出创建的连接对象的信息
print("连接成功!\n连接对象的基本信息如下:")
print (conn)
print (type(conn))
cursor = conn.cursor()
print("开始向数据表插入爬取的内容...")
sql1 = ("INSERT INTO score_table_test(学期,课程名,总成绩,课程性质,学分) VALUES(%s,%s,%s,%s,%s)")
for i in range(1,subject_num+1):
# param中是实际的表格数据
param = (total_container[i-1][1], total_container[i-1][2], total_container[i-1][6], total_container[i-1][9], total_container[i-1][11])
cursor.execute(sql1, param)
conn.commit()
print("插入成功!")
# 清空表格内容
print("正在清空当前表格内容...")
sql2 = ("truncate table score_table_test")
cursor.execute(sql2)
conn.commit()
print("删除成功!")
# 关闭指针对象和连接对象
print("准备断开数据库连接....")
cursor.close()
conn.close()
print("已成功断开连接!")
结果:
完整源码戳这里
欢迎小伙伴们fork or star其他项目哦~