本章内容包含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/
码字不易,感谢点赞评论收藏关注~