从零搭建教务抢课系统(三)


目录

(一)核心功能:模拟登陆
(二)使用Cookie进行模拟登录
(三)获取教务网选课列表
(四)循环选课
(五)断线重连

Github链接: https://github.com/njuwuyuxin/CourseGrabber

获取选课列表

在研究了教务网的js代码以及抓包分析之后,发现教务网拉取专业选课列表的接口接收不同数量的参数(有默认参数)
专业选课页面的加载逻辑为,初次进入页面自动发送一条post请求,请求体为

1
2
3
{
'method':'specialityCourseList'
}

该请求只包含调用的方法名,其余均为默认参数,用来拉取默认显示的课程列表

当用户在下拉选单中手动选择某项之后,会向同一端口再次发送一条post请求,请求体为

1
2
3
4
5
{
'method':'specialityCourseList',
'specialityCode':'221',
'courseGrade':'2016
}

这次请求体中包含了所在专业的专业编号,以及对应年级

解析网页获得课程列表

按照请求格式构造好请求体中,response返回的HTML文档就是包含了课程列表的页面
这里使用了Beautiful Soup进行解析,可以看到课程列表是以、 标签的形式进行显示,按对应格式解析即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
soup = BeautifulSoup(courseList.content,"html.parser",from_encoding='utf-8')
soup = BeautifulSoup(courseList.content,"html.parser",from_encoding='utf-8')
trs = soup.find_all('tr',{'class':'TABLE_TR_01'})
print("序号\t课程号\t\t课程名\t\t\t学分\t学时\t类型\t开课院系")
for tr in trs:
tds = tr.find_all('td')
courseNo = tds[0].find('a').find('u').string
if(tds[1].string.__len__()<=7):
print(str(trs.index(tr)+1)+'\t'+courseNo+'\t'+tds[1].string+'\t\t'+tds[2].string+'\t'+tds[3].string+'\t'+tds[4].string+'\t'+tds[6].string)
else:
print(str(trs.index(tr)+1)+'\t'+courseNo+'\t'+tds[1].string+'\t'+tds[2].string+'\t'+tds[3].string+'\t'+tds[4].string+'\t'+tds[6].string)
click_td = tr.find('td',{'onclick':True})
if click_td==None:
courseIdList.append("")
pass
else:
# print(click_td['onclick'])
js = click_td['onclick']
args = js.split(',')
courseID = args[4][0:5]
courseIdList.append(courseID)

由于教务网后端较为特殊,选课的请求体中课程id有单独编号需要提取,而不是使用课程编号(后文有讲),因此额外做了一些解析,HTML解析这里不具有普遍参考价值.

获取的课程列表展示如下:
课程列表

参考资料

Beautiful Soup4 中文文档