python爬虫学习(4) —— 手刃「URP教务系统」
0. 本爬虫目标
- 模拟登陆URP教务系统
- 查询 本学期/历年 成绩
- 计算历年成绩的绩点
下面是一点废「私」话「货」:
一般情况,查询成绩大家会通过如下方式:
登陆信息门户 -> 转到教学空间 -> 选择教务管理 -> 选择综合查询
最终可以看到你的成绩
吐槽一下,查询成绩必须使用IE内核的浏览器,在IE11中还需要设置兼容性,非IE内核的浏览器是无法查看成绩的。
好。我们查看一下源代码,或者凭经验可以发现,,这个「成绩」是嵌套在一个frame框架中的。
啊,,好蛋疼啊。。。。。
啊,,好蛋疼啊。。。。。
啊,,好蛋疼啊。。。。。
是的,,,事实上,,我们可以发现四个页面:
本学期成绩: http://bksjw.chd.edu.cn/bxqcjcxAction.do
学年成绩:http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=qbinfo&lnxndm
方案成绩:http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792
打印成绩:http://bksjw.chd.edu.cn/reportFiles/student/cj_zwcjd_all.jsp
抛开这些,试着点击一下注销,,我靠,我们从信息门户跳转到了URP教务系统。。
实际上,信息门户的系统只是以框架的形式将URP教务系统的页面嵌套进来,那就不奇怪了!
更神奇的是,,,,,啊,,在没有修改密码的情况下,, 所有人。。。。。是的,是所有人。。。。
*默认帐号密码都是自己的学号!!!!! 自己的学号,己的学号,的学号~~~~~*
所以,,,我们下面。直接拿URP来开刀,,,,查询成绩以及计算绩点!!
1. 模拟登陆URP教务系统
1.1 页面分析
- 打开IE浏览器 -> 按F12打开调试工具 -> 进入URP综合教务系统 的 主页
- 输入帐号密码,登陆系统,页面跳转,观察页面的信息
- IE下看不到表单数据,但是非IE内核却又不能查看成绩,怎么办,,先到非IE内核浏览器下查看表单数据,再回来?其实你可以用其他抓包工具啊,比如
httpwatch
吖。 - 另外一个问题需要明白,我们post的URL并非是主页
http://bksjw.chd.edu.cn/
而是`http://bksjw.chd.edu.cn/loginAction.do```,这个我们在分析过程中是可以发现的
- IE下看不到表单数据,但是非IE内核却又不能查看成绩,怎么办,,先到非IE内核浏览器下查看表单数据,再回来?其实你可以用其他抓包工具啊,比如
- 我们可以看到headers,cookies,postdata等我们需要的数据
模拟登陆的关键就是这个 Form Data
1.2 尝试登陆
#coding=utf-8
import urllib,urllib2,cookielib
# hosturl用于获取cookies, posturl是登陆请求的URL
hosturl = 'http://bksjw.chd.edu.cn/'
posturl = 'http://bksjw.chd.edu.cn/loginAction.do'
#获取cookies
cj = cookielib.LWPCookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
h = urllib2.urlopen(hosturl)
# 伪装成浏览器,反“反爬虫”——虽然我们学校的URP好像没有做反爬虫
headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)',
'Referer':'http://bksjw.chd.edu.cn/'}
# 构造POST数据 用户名和密码,,自行修改啊,,别乱来啊。
postData = {
'dllx':'dldl',
'zjh':'xxxx',
'mm':'xxxx' }
postData = urllib.urlencode(postData)
# 构造请求
request = urllib2.Request( posturl, postData, headers )
# 登陆
urllib2.urlopen(request)
2. 查询成绩
好的,我们成功模拟登陆URP系统,接下来。。继续分析吧。。。
查看源代码。。。发现,,这个URP系统是一个框架套一个框架。简直爆炸。。
没关系,我们仔细找,最终可以找到类似如下的地址,,是的,这正是我们需要的,其实就是我上面说的那四个。。。。。
我们接着写
#coding=utf-8
import urllib,urllib2,cookielib
# hosturl用于获取cookies, posturl是登陆请求的URL
hosturl = 'http://bksjw.chd.edu.cn/'
posturl = 'http://bksjw.chd.edu.cn/loginAction.do'
#获取cookies
cj = cookielib.LWPCookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
h = urllib2.urlopen(hosturl)
# 伪装成浏览器,反“反爬虫”——虽然我们学校的URP好像没有做反爬虫
headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)',
'Referer':'http://bksjw.chd.edu.cn/'}
# 构造POST数据
postData = {
'dllx':'dldl',
'zjh':'201224060201',
'mm':'XXXXXXXX' }
postData = urllib.urlencode(postData)
# 构造请求
request = urllib2.Request( posturl, postData, headers )
# 登陆
urllib2.urlopen(request)
# 用一个方案成绩做测试
testurl = 'http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792'
save = urllib2.urlopen(testurl).read()
open( 'score.html', "w").write(save)
可以看到,程序运行之后,桌面上产生了一个 score.html
我们查询到了自己的方案成绩,nice!
一个应该注意的问题
在linux下html可能会出现乱码,原因是,保存下来的html代码并没有指明编码方式,好蛋疼的代码啊
我们用如下方法来处理:
testurl = 'http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792'
head = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
save = head + urllib2.urlopen(testurl).read().decode('GBK').encode('UTF-8')
open( 'score.html', "w").write(save)
3. 计算绩点
还是看源代码,,发现,,,,好垃圾的代码,,好乱的代码。。。。。。无语
最后可以发现,每门成绩对应的html代码如下:
大框架是一个<tr>xxxxxxx</tr>
,,开始尝试写正则表达式
却发现又存在一个问题,,,空格好多,,而且代码好乱
怎么办。。。强行写了一个很难看的RE表达式:
reg = re.compile(r'<tr class="odd".*?>.*?<td.*?</td>.*?<td.*?</td>.*?<td.*?</td>.*?<td.*?</td>.*?<td align="center">\s*(\S+)\s*</td>.*?<td.*?</td>.*?<td align="center">.*?<p align="center">(.*?) .*?</P>.*?</td>.*?<td.*?</td>.*?</tr>.*?',re.S)
使用正则表达式匹配出每门课的学分和分数,相乘之后相加,最后再除以总学分数,就OK了
\]
然而,还有一个问题需要解决,,我的天,,,有些成绩给的是等级「优秀、良好之类云云」,而不是分数。
好吧,我们首先把字符统一转化为utf-8
,然后再进行判断,转化为浮点型进行计算
那就有了如下函数:
def calc_gpa(self):
reg = re.compile(r'<tr class="odd".*?>.*?<td.*?</td>.*?<td.*?</td>.*?<td.*?</td>.*?<td.*?</td>.*?<td align="center">\s*(\S+)\s*</td>.*?<td.*?</td>.*?<td align="center">.*?<p align="center">(.*?) .*?</P>.*?</td>.*?<td.*?</td>.*?</tr>.*?',re.S)
myItems = reg.findall(self.score_html)
score = []
credit = []
sum = 0.0
weight = 0.0
for item in myItems:
credit.append(item[0])
score.append(item[1])
for i in range(len(score)):
try:
we = float(credit[i])
add = float(score[i])
sum += add*we
weight += we
except:
if score[i] == "优秀":
sum += 95.0*we
weight += we
elif score[i] == "良好":
sum += 85.0*we
weight += we
elif score[i] == "中等":
sum += 75.0*we
weight += we
elif score[i] == "及格":
sum += 60.0*we
weight += we
else:
weight += we
if weight == 0 :
return
print 'your GPA is ', sum/weight
4. 最终成果
是的,最后我实现了以四种模式查看成绩,计算GPA两个功能。
5. 一点扩展
如果是在windows下,我们还可以 使用 PyInstaller 把python程序 .py转为 .exe 可执行程序
我只说一点,,,,切记不要放在中文目录,,否则你会死的很难看。。。。
6. 源代码
代码有点撮不是很想贴,,你可以在我的 github 中找到,算了,还是贴出来吧
#!/usr/bin/python
# -*- coding: utf-8 -*-
__author__ = 'BG'
import urllib, urllib2
import cookielib
import re
class URP:
def __init__(self,username,password):
self.usr = username
self.psw = password
self.hosturl = 'http://bksjw.chd.edu.cn/'
self.posturl = 'http://bksjw.chd.edu.cn/loginAction.do'
cj = cookielib.LWPCookieJar()
cookie_support = urllib2.HTTPCookieProcessor(cj)
opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
urllib2.install_opener(opener)
h = urllib2.urlopen(self.hosturl)
self.headers = {'User-Agent': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 10.0; WOW64; Trident/7.0; .NET4.0C; .NET4.0E; .NET CLR 2.0.50727; .NET CLR 3.0.30729; .NET CLR 3.5.30729)',
'Referer':'http://bksjw.chd.edu.cn/'}
self.postData = {'dllx':'dldl','zjh':self.usr,'mm':self.psw }
self.postData = urllib.urlencode(self.postData)
self.request = urllib2.Request( self.posturl, self.postData, self.headers )
def login(self):
flag = False
try:
urllib2.urlopen(self.request)
urllib2.urlopen('http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=qbinfo&lnxndm').read()
except urllib2.HTTPError, e:
print '-----------------------------------------------------------'
print 'Login Failed [%s], maybe your username or password is error!' %e.code
print '-----------------------------------------------------------'
else:
print '-----------------------------------------------------------'
print 'Login Successful'
print '-----------------------------------------------------------'
flag = True
return flag
def BXQ_score(self):
self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/bxqcjcxAction.do').read()
def NJ_score(self):
self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=qbinfo&lnxndm').read()
def TAB_score(self):
self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/reportFiles/student/cj_zwcjd_all.jsp').read()
def FA_score(self):
self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792').read()
def calc_gpa(self):
reg = re.compile(r'<tr class="odd".*?>.*?<td.*?</td>.*?<td.*?</td>.*?<td.*?</td>.*?<td.*?</td>.*?<td align="center">\s*(\S+)\s*</td>.*?<td.*?</td>.*?<td align="center">.*?<p align="center">(.*?) .*?</P>.*?</td>.*?<td.*?</td>.*?</tr>.*?',re.S)
myItems = reg.findall(self.score_html)
score = []
credit = []
sum = 0.0
weight = 0.0
for item in myItems:
credit.append(item[0])
score.append(item[1])
for i in range(len(score)):
try:
we = float(credit[i])
add = float(score[i])
sum += add*we
weight += we
except:
if score[i] == "优秀":
sum += 95.0*we
weight += we
elif score[i] == "良好":
sum += 85.0*we
weight += we
elif score[i] == "中等":
sum += 75.0*we
weight += we
elif score[i] == "及格":
sum += 60.0*we
weight += we
else:
weight += we
if weight == 0 :
return
print 'your GPA is ', sum/weight
def save_html(self):
fout=open("score.html","w")
head = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
self.score_html = head + self.score_html.decode('GBK').encode('UTF-8')
fout.write(self.score_html)
print '-----------------------------------------------------------'
print 'The result was saved in score.html\nGod bless you!!!!!!'
def query_score():
print 'Please input your username:'
usr = raw_input()
print 'Please input your password:'
psw = raw_input()
urp = URP(usr,psw)
if urp.login() == True:
print 'Please choose an mode:'
print '1 - your score of each subject in this term'
print '2 - all of your score in each term'
print '3 - all of your score in a table'
print '4 - all of your score by plan'
choose = raw_input()
if choose == '1':
urp.BXQ_score()
elif choose == '2':
urp.NJ_score()
elif choose == '3':
urp.TAB_score()
else:
urp.FA_score()
urp.save_html()
urp.calc_gpa()
else:
return
if __name__ == '__main__':
query_score()
raw_input ('Press Enter to exit!')
7. TODO
我又更新了一个 版本 ,可以获取自己的证件照。。其实就是入学时候的身份证照片。丑到爆。。
本来想把全年级同学的照片都爬下来,后来想想不是很道德。还是算了吧。
python爬虫学习(4) —— 手刃「URP教务系统」的更多相关文章
- python爬虫学习 —— 总目录
开篇 作为一个C党,接触python之后学习了爬虫. 和AC算法题的快感类似,从网络上爬取各种数据也很有意思. 准备写一系列文章,整理一下学习历程,也给后来者提供一点便利. 我是目录 听说你叫爬虫 - ...
- python爬虫学习(1) —— 从urllib说起
0. 前言 如果你从来没有接触过爬虫,刚开始的时候可能会有些许吃力 因为我不会从头到尾把所有知识点都说一遍,很多文章主要是记录我自己写的一些爬虫 所以建议先学习一下cuiqingcai大神的 Pyth ...
- Python爬虫学习:三、爬虫的基本操作流程
本文是博主原创随笔,转载时请注明出处Maple2cat|Python爬虫学习:三.爬虫的基本操作与流程 一般我们使用Python爬虫都是希望实现一套完整的功能,如下: 1.爬虫目标数据.信息: 2.将 ...
- Python爬虫学习:四、headers和data的获取
之前在学习爬虫时,偶尔会遇到一些问题是有些网站需要登录后才能爬取内容,有的网站会识别是否是由浏览器发出的请求. 一.headers的获取 就以博客园的首页为例:http://www.cnblogs.c ...
- Python爬虫学习:二、爬虫的初步尝试
我使用的编辑器是IDLE,版本为Python2.7.11,Windows平台. 本文是博主原创随笔,转载时请注明出处Maple2cat|Python爬虫学习:二.爬虫的初步尝试 1.尝试抓取指定网页 ...
- 《Python爬虫学习系列教程》学习笔记
http://cuiqingcai.com/1052.html 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多.学习过程中我把一些学习的笔记总结下来,还记录了一些自己 ...
- python爬虫学习视频资料免费送,用起来非常666
当我们浏览网页的时候,经常会看到像下面这些好看的图片,你是否想把这些图片保存下载下来. 我们最常规的做法就是通过鼠标右键,选择另存为.但有些图片点击鼠标右键的时候并没有另存为选项,或者你可以通过截图工 ...
- python爬虫学习笔记(一)——环境配置(windows系统)
在进行python爬虫学习前,需要进行如下准备工作: python3+pip官方配置 1.Anaconda(推荐,包括python和相关库) [推荐地址:清华镜像] https://mirrors ...
- [转]《Python爬虫学习系列教程》
<Python爬虫学习系列教程>学习笔记 http://cuiqingcai.com/1052.html 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多. ...
随机推荐
- The SQL Server Service Broker for the current database is not enabled
把一个数据恢复至另一个服务器上,出现了一个异常: The SQL Server Service Broker for the current database is not enabled, and ...
- Java 代码完成删除文件、文件夹操作
import java.io.File;/** * 删除文件和目录 * */public class DeleteFileUtil { /** * 删除文件,可以是文件或文件夹 ...
- C程序范例(1)——学生管理系统”数组“实现
1.在写程序之前,我想告诉大家,这个程序初学者很可能可能看不懂,但是这很正常,因为这是我在学习完C语言之后写的.所以大家好好学习吧! 由于这是在我大一刚学到数组时编写的程序,有许多冗余的部分,但当时做 ...
- LNMP环境搭建完整步骤
零.resource http://pan.baidu.com/s/1o83r3S2 一.centos 6.4.VirtualBox 5.0.14 二.nginx 1.9.9 安装 [root@p ...
- FacadePattern(门面模式)
/** * 外观模式(门面模式) * @author TMAC-J * 外观模式是通过访问一个前台来实现对子系统的访问,其和代理模式的区别是 * 代理模式是通过代理一个类的形式,也就是说一对一的关系 ...
- 从头开始搭建一个mybatis+postgresql平台
最近有个项目的数据库使用postgresql,使用原生态的mybatis操作数据,原生态的没什么不好,只不过国内有个tk.mybatis的工具帮助我们做了很多实用的事情,大多数情况下我们需要 ...
- Thinkcmf:页面常用函数
Thinkcmf:页面常用函数 全站seo: 文章列表: {$site_seo_title} <!--SEO标题--> {$site_seo_keywords} < ...
- checkbox & radio 的对齐问题
不仅不同浏览器不同,不同的字体,不同的文字大小也会表现不一样. 重置 form checkbox & radio 因为不同浏览器解析不一样,有些是默认margin,有些是默认padding,还 ...
- SAP RFC
什么是RFC? RFC是SAP系统和其他(SAP或非SAP)系统间的一个重要而常用的双向接口技术,也被视为SAP与外部通信的基本协议.简单地说,RFC过程就是系统调用当前系统外的程序模块,从而实现某个 ...
- GitHub学习心得之 简单操作
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 前言 本文对Github的基本操作进行了总结, 主要基于以下文章: http://gitre ...