本章内容包含python爬取中國海洋大學教務系統 2021年秋季學期 2018-2020年級所有計算機專業課 至excel。
系列文章目錄
第一章 python模拟登入中國海洋大學教務系統(青果)
第二章 爬取學期所有專業課至excel
第三章 課表排課
本來隻是想爬個課表,排個課,可惜不能直接爬,需要登入上教務網站,是以就有了第一篇文章。
文章目錄
- 系列文章目錄
- 前言
- 一、将表格内容寫入excel
- 二、使用循環,爬取2018-2020級的專業課
- 三、全部代碼及運作效果
- 四、遇到的問題
- 總結
前言
第一篇已經實作了登入教務網站,并跳轉至選課頁面,同時也有了頁面表格輸出。
因為是轉專業,每次進入都要選擇目标專業,還要選目标年級,很麻煩,是以想一次性把2018級到2020級的專業課都爬下來,之後再用算法排課。
一、将表格内容寫入excel
1.先觀察選課頁面的表格

表格中有兩列”教學大綱“”教學月曆“一直是空的,是以沒必要爬下來
再根據上一章爬下來的内容,可以知道表格中有幾列隐藏列也是空的,,是以也沒必要爬
需要安裝庫 pip install openpyxl
Python官方庫一般使用xlrd庫來讀取Excel檔案,使用xlwt庫來生成Excel檔案,使用xlutils庫複制和修改Excel檔案,這三個庫隻支援到Excel2003。
第三方庫openpyxl(可讀寫excel表),專門處理Excel2007及以上版本産生的xlsx檔案,xls和xlsx之間轉換容易。
該部分代碼:
from openpyxl import load_workbook,Workbook
def get_data(session):
...
...
table_node = soup.find_all('td')
for table in table_node:
if table.has_attr('style') == False: #不是隐藏列
if table.text != "教學大綱" and table.text != "教學月曆":
if table.has_attr('name'): #具有屬性name
if table['name'] != "jxdg" and table['name'] != "jxrl": #不是空列
sheet.cell(a,b,table.text) #寫入表格
else: #不具有屬性name
sheet.cell(a,b,table.text) #寫入表格
...
if __name__ == '__main__':
try:
wb = load_workbook('排課.xlsx') #加載薄
except:
wb = Workbook() #建立薄
sheet = wb.active #打開簿中第一個表
#sheet = wb.create_sheet() #建立表
...
wb.save('排課.xlsx')
二、使用循環,爬取2018-2020級的專業課
循環,傳參sel_nj-選擇的年級
主要是聲明兩個全局變量,控制行和列
變量隻是一個普通變量,首先在函數外部進行初始化,然後在函數内部通過global關鍵字呼叫這個變量,就可以實作全局變量的功能了。 ——python中的全局變量(global關鍵字)
該部分代碼:
a=1
b=1
def get_data(session, sel_nj): #選擇的年級
global a
global b
formdata={
...
'sel_nj': sel_nj,#選擇的年級2018-2020
...
}
...
...
for table in table_node:
if table.has_attr('style') == False: #不是隐藏列
if table.text != "教學大綱" and table.text != "教學月曆":
if table.has_attr('name'): #具有屬性name
if table['name'] != "jxdg" and table['name'] != "jxrl": #不是空列
sheet.cell(a,b,table.text) #寫入表格
b=b+1 #列加一
if table['name'] == "bz": #該換行了
b=1 #第一列
a=a+1 #行加一
else: #不具有屬性name
sheet.cell(a,b,table.text) #寫入表格
b=b+1
if table.text == "備注": #該換行了
b=1
a=a+1
...
def logon():
...
for i in range(2018,2021):
get_data(session,i)
...
三、全部代碼及運作效果
import requests
from aip import AipOcr
import base64
from hashlib import md5
import json
import re
from bs4 import BeautifulSoup
from time import time
#建立新薄 新表
from openpyxl import load_workbook,Workbook
a=1
b=1
headers = {
'Host': 'jwgl.ouc.edu.cn',
'Origin': 'http://jwgl.ouc.edu.cn',
'Referer': 'http://jwgl.ouc.edu.cn/cas/login.action',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest',
'Upgrade-Insecure-Requests': '1',
}
#data和headers一樣,并沒有傳全部的項
data = {
'randnumber': 'gqzd'
}
#百度智能雲-文字識别
def randnumber_ocr(image):
APP_ID = '' # 在百度官網的應用清單中檢視APP_ID
API_KEY = '' # 在百度官網的應用清單中檢視API_KEY
SECRET_KEY = '' # 在百度官網的應用清單中檢視SECRET_KEY
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
text = client.basicAccurate(image)
if text['words_result_num'] == 1:
return text['words_result'][0]['words'].strip()
else:
return ''
def get_data(session, sel_nj):
global a
global b
url = 'http://jwgl.ouc.edu.cn/taglib/DataTable.jsp?tableId=6146'
#這個data包含了所有項,但有些其實的非必須的
formdata={
'initQry': '0',
'xktype': '2',#選課類型
'xh': '',#你的學号
'xn': '2021',#學年
'xq': '1',#學期-夏0-秋1-春2
'nj': '',#你的年級
'zydm': '',#你的專業代碼
'items': '',
'xnxq': '2021-1',#學年-學期
'kcfw': 'Specialty',#課程範圍
'sel_nj': sel_nj,#選擇的年級2018-2020
'sel_zydm': '0011',#選擇的專業代碼
'sel_schoolarea': '',
'sel_cddwdm': '',
'sel_kc': '',
'kcmc': ''
}
#這個headers必須包含Referer
headers['Referer'] = 'http://jwgl.ouc.edu.cn/student/wsxk.kcbcx.html?menucode=JW130414'
#使用session
r = session.post(url,data=formdata, headers=headers)
soup = BeautifulSoup(r.text, 'html.parser')
table_node = soup.find_all('td')
for table in table_node:
if table.has_attr('style') == False: #不是隐藏列
if table.text != "教學大綱" and table.text != "教學月曆":
if table.has_attr('name'): #具有屬性name
if table['name'] != "jxdg" and table['name'] != "jxrl": #不是空列
sheet.cell(a,b,table.text) #寫入表格
b=b+1
if table['name'] == "bz": #該換行了 b == 15:#23
b=1
a=a+1
else:
sheet.cell(a,b,table.text) #寫入表格
b=b+1
if table.text == "備注": #該換行了 b == 15:#23
b=1
a=a+1
session.close()
def logon():
start = time()
url = 'http://jwgl.ouc.edu.cn/cas/logon.action'
username = '' # 輸入你的使用者名,也就是學号
password = '' # 輸入你的密碼
session = requests.Session()
#百度智能雲-文字識别-擷取驗證碼
randnumber = ''
while len(randnumber) != 4:
r = session.get('http://jwgl.ouc.edu.cn/cas/genValidateCode', headers=headers)
randnumber = randnumber_ocr(r.content).replace(' ','')#去除空格
#構造data-資訊加密
password = md5(password.encode('utf-8')).hexdigest()
randnumber_s = md5(randnumber.lower().encode('utf-8')).hexdigest()
password = md5((password + randnumber_s).encode('utf-8')).hexdigest()
#sessionid是會話的id,一般是存放在cookie中
_sessionid = session.cookies.get_dict()['JSESSIONID']
username = base64.b64encode(username.encode('utf-8') + b';;' + str(_sessionid).encode('utf-8'))
#randnumber會在之前通過百度智能雲文字識别獲得
data['randnumber'] = randnumber
p_username = '_u' + randnumber
p_password = '_p' + randnumber
data[p_username] = username
data[p_password] = password
#post
r = session.post(url, data=data, headers=headers)
#response
info = json.loads(r.text)
status = info['status']
if status == '401':
print('驗證碼錯誤')
return
elif status == '200':
pass
else:
print(info['message'])
return
print('登入成功')
for i in range(2018,2021):
get_data(session,i)
end = time()
print('總共用時' + str(end - start))
if __name__ == '__main__':
try:
wb = load_workbook('排課.xlsx') #加載薄
except:
wb = Workbook() #建立薄
sheet = wb.active #打開簿中第一個表
#sheet = wb['biaoge_name'] #打開薄中 名字為biaoge_name的表
#sheet = wb.create_sheet() #建立表
logon()
wb.save('排課.xlsx')
四、遇到的問題
TimeoutError: [WinError 10060] 由于連接配接方在一段時間後沒有正确答複或連接配接的主機沒有反應,連接配接嘗試失敗。
沒連 VPN
wb= load_workbook('排課.xlsx')#加載薄
NameError: name 'load_workbook' is not defined
要 from openpyxl import load_workbook
wb.creat_sheet('xinbiao2')
AttributeError: 'Workbook' object has no attribute 'creat_sheet'
create_sheet 拼寫錯誤
sheet.cell(a,b,table.text)
ValueError: Row or column values must be at least 1
cell 的行和列都要從1開始
這種 KeyError 錯誤一般都是因為沒有這個東西,
以本程式為例,有些table含有name屬性,有些不含,如果不加判斷的去寫就會報錯
隻能是 tag.text 和 tag[‘id’]、tag[‘name’]
這個不太确定,看别人有用 tag.id/name
但本程式是 tag.id/name = None
總結
1.全局變量,首先在函數外部進行初始化,然後在函數内部通過global關鍵字呼叫這個變量。
·
a=1
·
·
def func:
·
········
a=a+1
·
2.python沒有a++
3.進行解析後,Tag是否具有某種屬性
·
if table.has_attr('name'): #具有屬性name
·
4.篩選具有某種屬性的Tag
關于python:測試BeautifulSoup中的标簽中是否存在屬性
·
script_tags = soup.find_all('script', some_attribute=True)
·
·
script_tags = soup.find_all('script', {"some-data-attribute": True})
·
5.為什麼要from … import …
python中為什麼大佬都愛用from import
因為導入包名其實是無法直接使用包内的子包和子產品的
6.openpyxl
python之openpyxl子產品
openpyxl中有三個不同層次的類 | Workbook是對工作簿的抽象 | Worksheet是對表格的抽象 | Cell是對單元格的抽象 | 每一個類都包含了許多屬性和方法 |
---|---|---|---|---|
Excel基本操作 | 打開或者建立一個Excel,需要建立一個Workbook對象 | 使用Workbook對象的方法來得到一個Worksheet對象 | 得到Worksheet對象以後再從中擷取代表單元格的Cell對象 |
常用:
·
wb = load_workbook('排課.xlsx') #加載薄
·
·
wb = Workbook() #建立薄
·
·
sheet = wb.active #打開簿中第一個表
·
·
sheet = wb['biaoge_name'] #打開薄中 名字為biaoge_name的表
·
·
sheet = wb.create_sheet() #建立表
·
·
sheet.cell(行,列,内容) #修改單元格内容
·
·
wb.save('排課.xlsx') #儲存薄
·
收獲多多 \OoO/
碼字不易,感謝點贊評論收藏關注~