我们学校的教务网是强智科技的,平时必须IE才能打开,而我用Chrome,所以我做了这么一个爬虫工具,方便自己查阅教务网成绩,希望对你有帮助~
用到的python库:re、requests
爬虫思路(xxx代表教务网网址,不便传播)
- 创建一个Requests会话对象(所有的爬虫步骤都在该会话下进行)。
1s = requests.Session()
- get教务网的登陆页面,返回的头部信息中的cookies信息。
1r = s.get(r'http://xxxxxxxxx/', headers=kdjw_hed)
2cookies = r.headers['Set-Cookie'][0:-12]
- 根据获取到cookies信息实时获取当前登录页面的验证码图片信息,并把它的二进制文件信息存储为code.jpg。
1r_verifycode = s.get(r'http://xxxxxxxxx/verifycode.servlet', headers=verifycode_hed)
2with open('code.jpg','wb') as f:
3 f.write(r_verifycode.content)
- 请求用户输入验证码,然后把所收到的验证码字符串以及用户输入的学号,密码POST到真正的登录的页面,进而实现模拟登陆。
1r_login = s.post(r'http://xxxxxxxxx/Logon.do?method=logon', headers=post_hed, data=login_data)
- 模拟登陆后,先用regex匹配所要获取的成绩数据所在页面的页数,然后再向该url提交查询参数(params),例如:'kksj':开课时间;'PageNum':页码,使用for循环,进而获取到每一页的成绩数据。
1regex = re.compile(r'name = "totalPages" value="(.*?)"')
1#示例:某一页
2r_page = s.get(r'http://xxxxxxxxx/xszqcjglAction.do?method=queryxscj', headers=query_hed, params=page_param, timeout=3)
获取到成绩信息的原始数据之后,我们就可以进行数据的清洗和整理了~
该思路的源代码(代码并不能直接运行)
1#import sys
2#import io
3import re
4import requests
5#from PIL import Image
6
7#改变标准输出的默认编码 8#sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf8')
9
10def get_cookies():
11 '从kdjw/的Set-Cookie获取整个会话的cookies'
12 kdjw_hed = {'Host': 'xxxxxxxxx',
13 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',}
14 r = s.get(r'http://xxxxxxxxx/',headers=kdjw_hed, timeout=3)
15 #print(r.headers)
16 #获取到cookies
17 cookies = r.headers['Set-Cookie'][0:-12]
18 return cookies
19
20def get_verifycode(cookies):
21 '根据所得cookies获取验证码'
22 verifycode_hed = {'Cookie': cookies,
23 'Host': 'xxxxxxxxx',
24 'Referer': 'http://xxxxxxxxx/',
25 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',}
26 #验证码获取
27 r_verifycode = s.get(r'http://xxxxxxxxx/verifycode.servlet', headers=verifycode_hed, timeout=3)
28
29 with open('code.jpg','wb') as f:
30 f.write(r_verifycode.content)
31 return True
32
33#def show_verifycode():
34# '通过Image模块展示验证码图片,并提示用户输入验证码'
35# im = Image.open('code.jpg')
36# im.show()
37# verifycode = input('请输入验证码: ')
38# return verifycode
39
40def virtual_login(verifycode, cookies, usr, pwd):
41 '虚拟登陆教务网'
42 #模拟登陆
43 login_data = {'useDogCode': '',
44 'USERNAME': usr,
45 'PASSWORD': pwd,
46 'RANDOMCODE': verifycode}
47 post_hed = {'Cookie': cookies,
48 'Host': 'xxxxxxxxx',
49 'Origin': 'http://xxxxxxxxx',
50 'Referer': 'http://xxxxxxxxx/',
51 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
52 }
53 r_login = s.post(r'http://xxxxxxxxx/Logon.do?method=logon', headers=post_hed, data=login_data, timeout=3)
54 #验证登陆
55 r_verifylogin = s.get(r'http://xxxxxxxxx/framework/main.jsp', headers=post_hed)
56 regex = re.compile(r'<title>XXXX大学数字化校园平台-XX科技</title>')
57 verifylogin = regex.search(r_verifylogin.text)
58 if verifylogin:
59 return False
60 else:
61 return True
62
63def search_and_get_grades_html(cookies, kksj):
64 '模拟登陆之后,打开成绩查询页面获取并返回成绩源数据'
65 #成绩查询,针对不止一页成绩数据的情况进行优化
66 form_data = {'kksj': kksj, 'kcxz': '', 'kcmc': '', 'xsfs': 'qbcj', 'ok':'', }
67 query_hed = {'Cookie': cookies,
68 'Host': 'xxxxxxxxx',
69 'Origin': 'http://xxxxxxxxx/',
70 'Referer': 'http://xxxxxxxxx/jiaowu/cjgl/xszq/query_xscj.jsp',
71 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',}
72 r_grade = s.post('http://xxxxxxxxx/xszqcjglAction.do?method=queryxscj', headers=query_hed, data=form_data, timeout=3)
73 #获取总页数
74 regex = re.compile(r'name = "totalPages" value="(.*?)"')
75 totalpages = int(regex.findall(r_grade.text)[-1])
76 #按页数获取成绩数据
77 if totalpages == 1:
78 print('成功获取第1页成绩数据!!! 共1页.',cookies)
79 return r_grade.text
80 else:
81 html_texts = r_grade.text
82 print('成功获取第1页成绩数据!!! 共%d页.' % totalpages, cookies)
83 query_hed.update({'Referer': 'http://xxxxxxxxx/xszqcjglAction.do?method=queryxscj'})
84 #print(query_hed)
85 for pagenum in range(2,totalpages+1):
86 #巧用params
87 page_param = {'PageNum':pagenum, 'kksj':kksj}
88 r_page = s.get(r'http://xxxxxxxxx/xszqcjglAction.do?method=queryxscj', headers=query_hed, params=page_param, timeout=3)
89 html_texts += r_page.text
90 print('成功获取第%d页成绩数据!!! 共%d页.' % (pagenum, totalpages), kksj, cookies)
91 return html_texts
92
93def get_code_in_file():
94 '创建会话,获取cookies,依此获取并保存验证码图片'
95 global s, cookies_
96 s = requests.Session()
97 #cookies
98 cookies_ = get_cookies()
99 #更新验证码code.jpg
100 get_verifycode(cookies_)
101 return cookies_
102
103def main(verifycode_, cookies_, usr_, pwd_, kksj_):
104 '模拟登陆,验证登陆后获取并返回成绩源数据'
105 orignal_html = '' #初始化变量orignal_html
106 login = virtual_login(verifycode_, cookies_, usr_, pwd_)
107 if login:
108 orignal_html = search_and_get_grades_html(cookies_, kksj_)
109 #print(orignal_html)110 return orignal_html
经过一番手动测试,发现之前我获取到的仅仅是第一页的成绩数据。对于成绩数据大于一页的同学就显示不了了。
现在,我对之前的代码进行了部分精简和修改,爬虫的正确功能已经实现了,此处应有掌声~
但是,在教务网打不开(大部分情况可能是服务器在未通知的情况下进行维护)的时候,成绩数据是无法获取的。(2018.7.13 22:54, Modified)