最近看了CSDN上一个专栏《
具体过程专栏作者写得很清楚,详见
根据那篇博文,整个过程分为以下几步:
打开教务系统网站,查看登陆时发送了哪些信息,分析POST和GET信息,并在模拟登陆时使用;
进入网站后,查看如何与网站交互,同步骤一,分析这些信息,在模拟查询时使用;
使用爬虫模拟登陆和查询,得到成绩页面的html代码;
使用正则表达式提取得到的html代码中的所有成绩信息;
通过提取到的成绩信息计算平均学分绩。
具体操作细节可以参考上面那篇博文。此处不再赘述。
这里写一下我遇到的问题。上述博文中,作者登陆成绩查询系统后,直接找到成绩查询页面的URL就可以得到成绩页面的html代码,而在我们学校的教务系统中我却怎么也找不到该URL。经过N多次实验发现,我们学校查询的时候也会发送一个特定格式的POST信息,然后才会返回成绩页面,也就是说得再次模拟发送一次浏览成绩信息。感觉是由于自己对网站相关知识不了解,认为只要模仿就能取得结果,殊不知这里查询方式的不同,浪费了不少时间。
得到网页信息后,就需要写正则表达式来提取成绩信息。关于Python的正则表达式详见:
附上源代码:
1 #-*- coding: utf-8 -*-
2 #author: Kill Console
3 #功能:计算西工大研究生本学期成绩学分绩
4
5 importurllib6 importurllib27 importcookielib8 importre9
10 REQUIRED = '\xe5\xad\xa6\xe4\xbd\x8d\xe5\xbf\x85\xe4\xbf\xae\xe8\xaf\xbe' #必修
11 ELECTIVE = '\xe5\xad\xa6\xe4\xbd\x8d\xe9\x80\x89\xe4\xbf\xae\xe8\xaf\xbe' #选修
12
13 classNPUSpider:14 def __init__(self, stuid, pwd):15 self.login_url = 'http://222.24.211.70/grsadmin/servlet/studentLogin' #登陆url
16 self.query_url = 'http://222.24.211.70/grsadmin/servlet/studentMain' #成绩查询url
17 self.cookie_jar = cookielib.CookieJar() #初始化一个CookieJar来处理Cookie的信息
18 self.post_data_login = urllib.urlencode({'TYPE':'AUTH', 'glhj':'', 'USER':stuid, 'PASSWORD':pwd}) #POST登录数据
19 self.post_data_query = urllib.urlencode({'MAIN_TYPE':'3', 'MAIN_SUB_ACTION':'浏览成绩', 'MAIN_NEXT_ACTION':'LL', 'MAIN_PURPOSE':'/jsp/student_JhBrow.jsp'}) #POST查询数据
20 self.opener =urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie_jar))21 self.course_data = [] #存储一门课的信息,包括课程号、课程名、学分、成绩等
22 self.weights = [] #存储学分
23 self.scores = [] #存储成绩
24 self.GPA = 0.0
25
26 definit_spider(self):27 req_login = urllib2.Request(url = self.login_url, data = self.post_data_login) #自定义一个登录请求
28 result_login = self.opener.open(req_login) #访问登录页面
29 req_query = urllib2.Request(url = self.query_url, data = self.post_data_query) #自定义一个查询请求
30 result_query = self.opener.open(req_query) #访问成绩页面
31 self.process_data(result_query.read().decode('gbk').encode('utf-8')) #由于存在中文,先解码再编码
32 self.calculate_GPA()33
34 defprocess_data(self, res_page):35 self.course_data = re.findall(r'
(.*?).*?(.*?).*?\s+(.*?)\s+.*?(.*?).*?(.*?).*?(.*?).*?(.*?).*?', res_page, re.S)36 for item inself.course_data:37 self.weights.append(item[4])38 self.scores.append(item[5])3940 defcalculate_GPA(self):41 sum_score = 0.0
42 sum_weight = 0.0
43 for i inrange(len(self.course_data)):44 if self.course_data[i][2] == REQUIRED and self.scores[i].isdigit(): #判断该科目是否是必修且是否有分数,若是则进行计算
45 sum_score += float(self.weights[i]) *float(self.scores[i])46 sum_weight +=float(self.weights[i])47 self.GPA = sum_score /sum_weight48
49 defprint_GPA(self):50 print u'课程代码\t\t类型\t\t学期\t\t学分\t\t成绩\t\t得分日期\t\t课程名称'
51 print '-'*120
52 for item inself.course_data:53 if item[2] ==REQUIRED:54 rqd = '\xe5\xad\xa6\xe4\xbd\x8d\xe5\xbf\x85\xe4\xbf\xae\xe8\xaf\xbe'
55 print '%s\t\t%s\t%s\t\t%s\t\t%s\t\t%s\t\t%s' % (item[0], rqd, item[3], item[4], item[5], item[6], item[1])56 else:57 print '%s\t\t%s\t%s\t\t%s\t\t%s\t\t%s\t\t%s' % (item[0], item[2], item[3], item[4], item[5], item[6], item[1])58 print
59 print 'The GPA is %.4f' %self.GPA60
61
62 defmain():63 stuid = raw_input('student ID:').strip()64 pwd = raw_input('pass word:').strip()65
66 spider =NPUSpider(stuid, pwd)67 spider.init_spider()68 spider.print_GPA()69
70 if __name__ == '__main__':71 main()
以下是一个西工大本科生学分绩计算脚本,由于测试时没有进行教学评估的查询不了,只能查询本学期成绩,所以计算的是本学期成绩学分绩(只计算必修):
1 #-*- coding: utf-8 -*-
2 #author: Kill Console
3 #功能:计算西工大本科生本学期成绩学分绩
4
5 importurllib6 importurllib27 importcookielib8 importre9
10 REQUIRED = '\xe5\xbf\x85\xe4\xbf\xae' #必修
11 ELECTIVE = '\xe4\xbb\xbb\xe9\x80\x89' #选修
12
13 classNPUSpider:14 def __init__(self, stuid, pwd):15 self.login_url = 'http://jw.nwpu.edu.cn/loginAction.do' #登陆url
16 self.result_url = 'http://jw.nwpu.edu.cn/bxqcjcxAction.do' #本学期成绩查询url
17 self.cookie_jar = cookielib.CookieJar() #初始化一个CookieJar来处理Cookie的信息
18 self.post_data = urllib.urlencode({'zjh':stuid, 'mm':pwd}) #POST的数据
19 self.opener =urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookie_jar))20 self.course_data = [] #存储一门课的信息,包括课程号、课程名、学分、成绩等
21 self.weights = [] #存储学分
22 self.scores = [] #存储成绩
23 self.GPA = 0.0
24
25 definit_spider(self):26 req = urllib2.Request(url = self.login_url, data = self.post_data) #自定义一个请求
27 result = self.opener.open(req) #访问登录页面
28 result = self.opener.open(self.result_url) #访问成绩页面
29 self.process_data(result.read().decode('gbk').encode('utf-8'))30 self.calculate_GPA()31
32 defprocess_data(self, res_page):33 self.course_data = re.findall(r'
', res_page, re.S)34 for item inself.course_data:35 self.weights.append(item[4])36 self.scores.append(item[6])3738 defcalculate_GPA(self):39 sum_score = 0.0
40 sum_weight = 0.0
41 for i inrange(len(self.course_data)):42 if self.course_data[i][5] == REQUIRED andself.scores[i].isdigit():43 sum_score += float(self.weights[i]) *float(self.scores[i])44 sum_weight +=float(self.weights[i])45 self.GPA = sum_score /sum_weight46
47 defprint_GPA(self):48 print 'The GPA is %.4f' %self.GPA49
50 defmain():51 stuid = raw_input('student ID:').strip()52 pwd = raw_input('pass word:').strip()53
54 spider =NPUSpider(stuid, pwd)55 spider.init_spider()56 spider.print_GPA()57
58 if __name__ == '__main__':59 main()
View Code