这是一篇介绍如何通过Python实现模拟登陆学校教务系统并爬取成绩相关信息(学期,课程名,总成绩,课程性质,学分)然后绘制成绩分布折线图最后导入MySQL数据库中的文章。 为了利用充分利用selenium的功能和成功爬取数据,需要有前置的html、css、简单爬虫的相关知识。 说明:我学校的成绩查询页面是通过加载js框架进而动态实时加载显示表格及数据的,如果仅仅是用一般的爬虫方法直接爬取页面信息,是不能成功的,因为那样是直接获取网页源码,其中并没有成绩数据。当然,采用某些爬虫方法肯定也能实现爬取js动态网页,但是我为了简单起见,直接用了selenium模拟登陆系统然后爬取信息。
一、导入主要模块 1 2 3 4 5 6 7 from bs4 import BeautifulSoup from selenium import webdriverfrom selenium.webdriver import ActionChainsfrom selenium.webdriver.common.keys import Keysimport matplotlib.pyplot as pltimport timeimport pymysql
二、利用selenium模拟登陆教务系统 1.首先给出系统登陆页面url和成绩查询页面url(方便登陆成功后直接跳转,省去了鼠标点击相关链接的操作)
1 2 3 url_login_page = ("你学校的教务系统登录页面url" ) url_cjcx=("成绩查询页面url" )
2.打开系统登录页面
1 2 3 4 5 6 7 8 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找到了所需的输入框及按钮)
1 2 3 4 5 6 7 8 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.在新页面打开成绩查询页面
1 2 3 driver.switch_to.window(driver.window_handles[-1 ]) driver.get(url_cjcx)
2.等待成绩查询页面加载完毕 我学校的查询页面与学校数据库对接较缓慢,所以我设置了10s等待时间,否则页面加载不出来会报错
3.找到“每页显示50条数据”的按钮并点击 这里我想点击“每页显示50条数据”按钮是因为这样可以直接爬取所有数据而不需要点击“下一页”按钮。同样地,这里根据个人需要调整参数即可
1 2 3 4 5 6 7 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的方法获取当前页面的源码然后采用一般的爬虫方法获取相关信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 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 = [] 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画图
1 2 3 4 5 6 7 8 9 print ("\n正在绘制成绩分布折线图..." )x = range (subject_num) plt.plot(x, score) plt.xlabel("Subject(The xth)" ) plt.ylabel("Score" ) plt.title('Score Distribution Chart' ) plt.show()
结果:
五、将数据导入MySQL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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 = (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 ("已成功断开连接!" )
结果: