0. 本爬虫目标

  • 模拟登陆URP教务系统
  • 查询 本学期/历年 成绩
  • 计算历年成绩的绩点

下面是一点废「私」话「货」:

一般情况,查询成绩大家会通过如下方式:

  1. 登陆信息门户 -> 转到教学空间 -> 选择教务管理 -> 选择综合查询

最终可以看到你的成绩

吐槽一下,查询成绩必须使用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```,这个我们在分析过程中是可以发现的

  • 我们可以看到headers,cookies,postdata等我们需要的数据

模拟登陆的关键就是这个 Form Data

1.2 尝试登陆

  1. #coding=utf-8
  2. import urllib,urllib2,cookielib
  3. # hosturl用于获取cookies, posturl是登陆请求的URL
  4. hosturl = 'http://bksjw.chd.edu.cn/'
  5. posturl = 'http://bksjw.chd.edu.cn/loginAction.do'
  6. #获取cookies
  7. cj = cookielib.LWPCookieJar()
  8. cookie_support = urllib2.HTTPCookieProcessor(cj)
  9. opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
  10. urllib2.install_opener(opener)
  11. h = urllib2.urlopen(hosturl)
  12. # 伪装成浏览器,反“反爬虫”——虽然我们学校的URP好像没有做反爬虫
  13. 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)',
  14. 'Referer':'http://bksjw.chd.edu.cn/'}
  15. # 构造POST数据 用户名和密码,,自行修改啊,,别乱来啊。
  16. postData = {
  17. 'dllx':'dldl',
  18. 'zjh':'xxxx',
  19. 'mm':'xxxx' }
  20. postData = urllib.urlencode(postData)
  21. # 构造请求
  22. request = urllib2.Request( posturl, postData, headers )
  23. # 登陆
  24. urllib2.urlopen(request)

2. 查询成绩

好的,我们成功模拟登陆URP系统,接下来。。继续分析吧。。。

查看源代码。。。发现,,这个URP系统是一个框架套一个框架。简直爆炸。。

没关系,我们仔细找,最终可以找到类似如下的地址,,是的,这正是我们需要的,其实就是我上面说的那四个。。。。。

我们接着写

  1. #coding=utf-8
  2. import urllib,urllib2,cookielib
  3. # hosturl用于获取cookies, posturl是登陆请求的URL
  4. hosturl = 'http://bksjw.chd.edu.cn/'
  5. posturl = 'http://bksjw.chd.edu.cn/loginAction.do'
  6. #获取cookies
  7. cj = cookielib.LWPCookieJar()
  8. cookie_support = urllib2.HTTPCookieProcessor(cj)
  9. opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
  10. urllib2.install_opener(opener)
  11. h = urllib2.urlopen(hosturl)
  12. # 伪装成浏览器,反“反爬虫”——虽然我们学校的URP好像没有做反爬虫
  13. 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)',
  14. 'Referer':'http://bksjw.chd.edu.cn/'}
  15. # 构造POST数据
  16. postData = {
  17. 'dllx':'dldl',
  18. 'zjh':'201224060201',
  19. 'mm':'XXXXXXXX' }
  20. postData = urllib.urlencode(postData)
  21. # 构造请求
  22. request = urllib2.Request( posturl, postData, headers )
  23. # 登陆
  24. urllib2.urlopen(request)
  25. # 用一个方案成绩做测试
  26. testurl = 'http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792'
  27. save = urllib2.urlopen(testurl).read()
  28. open( 'score.html', "w").write(save)

可以看到,程序运行之后,桌面上产生了一个 score.html 我们查询到了自己的方案成绩,nice!

一个应该注意的问题

在linux下html可能会出现乱码,原因是,保存下来的html代码并没有指明编码方式,好蛋疼的代码啊

我们用如下方法来处理:

  1. testurl = 'http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792'
  2. head = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
  3. save = head + urllib2.urlopen(testurl).read().decode('GBK').encode('UTF-8')
  4. open( 'score.html', "w").write(save)

3. 计算绩点

还是看源代码,,发现,,,,好垃圾的代码,,好乱的代码。。。。。。无语

最后可以发现,每门成绩对应的html代码如下:

大框架是一个<tr>xxxxxxx</tr>,,开始尝试写正则表达式

却发现又存在一个问题,,,空格好多,,而且代码好乱

怎么办。。。强行写了一个很难看的RE表达式:

  1. 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">(.*?)&nbsp.*?</P>.*?</td>.*?<td.*?</td>.*?</tr>.*?',re.S)

使用正则表达式匹配出每门课的学分和分数,相乘之后相加,最后再除以总学分数,就OK了

\[GPA =\frac{\sum credit \times grade }{\sum credit }
\]

然而,还有一个问题需要解决,,我的天,,,有些成绩给的是等级「优秀、良好之类云云」,而不是分数。

好吧,我们首先把字符统一转化为utf-8,然后再进行判断,转化为浮点型进行计算

那就有了如下函数:

  1. def calc_gpa(self):
  2. 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">(.*?)&nbsp.*?</P>.*?</td>.*?<td.*?</td>.*?</tr>.*?',re.S)
  3. myItems = reg.findall(self.score_html)
  4. score = []
  5. credit = []
  6. sum = 0.0
  7. weight = 0.0
  8. for item in myItems:
  9. credit.append(item[0])
  10. score.append(item[1])
  11. for i in range(len(score)):
  12. try:
  13. we = float(credit[i])
  14. add = float(score[i])
  15. sum += add*we
  16. weight += we
  17. except:
  18. if score[i] == "优秀":
  19. sum += 95.0*we
  20. weight += we
  21. elif score[i] == "良好":
  22. sum += 85.0*we
  23. weight += we
  24. elif score[i] == "中等":
  25. sum += 75.0*we
  26. weight += we
  27. elif score[i] == "及格":
  28. sum += 60.0*we
  29. weight += we
  30. else:
  31. weight += we
  32. if weight == 0 :
  33. return
  34. print 'your GPA is ', sum/weight

4. 最终成果

是的,最后我实现了以四种模式查看成绩,计算GPA两个功能。

5. 一点扩展

如果是在windows下,我们还可以 使用 PyInstaller 把python程序 .py转为 .exe 可执行程序

我只说一点,,,,切记不要放在中文目录,,否则你会死的很难看。。。。

6. 源代码

代码有点撮不是很想贴,,你可以在我的 github 中找到,算了,还是贴出来吧

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. __author__ = 'BG'
  4. import urllib, urllib2
  5. import cookielib
  6. import re
  7. class URP:
  8. def __init__(self,username,password):
  9. self.usr = username
  10. self.psw = password
  11. self.hosturl = 'http://bksjw.chd.edu.cn/'
  12. self.posturl = 'http://bksjw.chd.edu.cn/loginAction.do'
  13. cj = cookielib.LWPCookieJar()
  14. cookie_support = urllib2.HTTPCookieProcessor(cj)
  15. opener = urllib2.build_opener(cookie_support, urllib2.HTTPHandler)
  16. urllib2.install_opener(opener)
  17. h = urllib2.urlopen(self.hosturl)
  18. 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)',
  19. 'Referer':'http://bksjw.chd.edu.cn/'}
  20. self.postData = {'dllx':'dldl','zjh':self.usr,'mm':self.psw }
  21. self.postData = urllib.urlencode(self.postData)
  22. self.request = urllib2.Request( self.posturl, self.postData, self.headers )
  23. def login(self):
  24. flag = False
  25. try:
  26. urllib2.urlopen(self.request)
  27. urllib2.urlopen('http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=qbinfo&lnxndm').read()
  28. except urllib2.HTTPError, e:
  29. print '-----------------------------------------------------------'
  30. print 'Login Failed [%s], maybe your username or password is error!' %e.code
  31. print '-----------------------------------------------------------'
  32. else:
  33. print '-----------------------------------------------------------'
  34. print 'Login Successful'
  35. print '-----------------------------------------------------------'
  36. flag = True
  37. return flag
  38. def BXQ_score(self):
  39. self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/bxqcjcxAction.do').read()
  40. def NJ_score(self):
  41. self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=qbinfo&lnxndm').read()
  42. def TAB_score(self):
  43. self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/reportFiles/student/cj_zwcjd_all.jsp').read()
  44. def FA_score(self):
  45. self.score_html = urllib2.urlopen('http://bksjw.chd.edu.cn/gradeLnAllAction.do?type=ln&oper=fainfo&fajhh=3792').read()
  46. def calc_gpa(self):
  47. 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">(.*?)&nbsp.*?</P>.*?</td>.*?<td.*?</td>.*?</tr>.*?',re.S)
  48. myItems = reg.findall(self.score_html)
  49. score = []
  50. credit = []
  51. sum = 0.0
  52. weight = 0.0
  53. for item in myItems:
  54. credit.append(item[0])
  55. score.append(item[1])
  56. for i in range(len(score)):
  57. try:
  58. we = float(credit[i])
  59. add = float(score[i])
  60. sum += add*we
  61. weight += we
  62. except:
  63. if score[i] == "优秀":
  64. sum += 95.0*we
  65. weight += we
  66. elif score[i] == "良好":
  67. sum += 85.0*we
  68. weight += we
  69. elif score[i] == "中等":
  70. sum += 75.0*we
  71. weight += we
  72. elif score[i] == "及格":
  73. sum += 60.0*we
  74. weight += we
  75. else:
  76. weight += we
  77. if weight == 0 :
  78. return
  79. print 'your GPA is ', sum/weight
  80. def save_html(self):
  81. fout=open("score.html","w")
  82. head = '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
  83. self.score_html = head + self.score_html.decode('GBK').encode('UTF-8')
  84. fout.write(self.score_html)
  85. print '-----------------------------------------------------------'
  86. print 'The result was saved in score.html\nGod bless you!!!!!!'
  87. def query_score():
  88. print 'Please input your username:'
  89. usr = raw_input()
  90. print 'Please input your password:'
  91. psw = raw_input()
  92. urp = URP(usr,psw)
  93. if urp.login() == True:
  94. print 'Please choose an mode:'
  95. print '1 - your score of each subject in this term'
  96. print '2 - all of your score in each term'
  97. print '3 - all of your score in a table'
  98. print '4 - all of your score by plan'
  99. choose = raw_input()
  100. if choose == '1':
  101. urp.BXQ_score()
  102. elif choose == '2':
  103. urp.NJ_score()
  104. elif choose == '3':
  105. urp.TAB_score()
  106. else:
  107. urp.FA_score()
  108. urp.save_html()
  109. urp.calc_gpa()
  110. else:
  111. return
  112. if __name__ == '__main__':
  113. query_score()
  114. raw_input ('Press Enter to exit!')

7. TODO

我又更新了一个 版本 ,可以获取自己的证件照。。其实就是入学时候的身份证照片。丑到爆。。

本来想把全年级同学的照片都爬下来,后来想想不是很道德。还是算了吧。

python爬虫学习(4) —— 手刃「URP教务系统」的更多相关文章

  1. python爬虫学习 —— 总目录

    开篇 作为一个C党,接触python之后学习了爬虫. 和AC算法题的快感类似,从网络上爬取各种数据也很有意思. 准备写一系列文章,整理一下学习历程,也给后来者提供一点便利. 我是目录 听说你叫爬虫 - ...

  2. python爬虫学习(1) —— 从urllib说起

    0. 前言 如果你从来没有接触过爬虫,刚开始的时候可能会有些许吃力 因为我不会从头到尾把所有知识点都说一遍,很多文章主要是记录我自己写的一些爬虫 所以建议先学习一下cuiqingcai大神的 Pyth ...

  3. Python爬虫学习:三、爬虫的基本操作流程

    本文是博主原创随笔,转载时请注明出处Maple2cat|Python爬虫学习:三.爬虫的基本操作与流程 一般我们使用Python爬虫都是希望实现一套完整的功能,如下: 1.爬虫目标数据.信息: 2.将 ...

  4. Python爬虫学习:四、headers和data的获取

    之前在学习爬虫时,偶尔会遇到一些问题是有些网站需要登录后才能爬取内容,有的网站会识别是否是由浏览器发出的请求. 一.headers的获取 就以博客园的首页为例:http://www.cnblogs.c ...

  5. Python爬虫学习:二、爬虫的初步尝试

    我使用的编辑器是IDLE,版本为Python2.7.11,Windows平台. 本文是博主原创随笔,转载时请注明出处Maple2cat|Python爬虫学习:二.爬虫的初步尝试 1.尝试抓取指定网页 ...

  6. 《Python爬虫学习系列教程》学习笔记

    http://cuiqingcai.com/1052.html 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多.学习过程中我把一些学习的笔记总结下来,还记录了一些自己 ...

  7. python爬虫学习视频资料免费送,用起来非常666

    当我们浏览网页的时候,经常会看到像下面这些好看的图片,你是否想把这些图片保存下载下来. 我们最常规的做法就是通过鼠标右键,选择另存为.但有些图片点击鼠标右键的时候并没有另存为选项,或者你可以通过截图工 ...

  8. python爬虫学习笔记(一)——环境配置(windows系统)

    在进行python爬虫学习前,需要进行如下准备工作: python3+pip官方配置 1.Anaconda(推荐,包括python和相关库)   [推荐地址:清华镜像] https://mirrors ...

  9. [转]《Python爬虫学习系列教程》

    <Python爬虫学习系列教程>学习笔记 http://cuiqingcai.com/1052.html 大家好哈,我呢最近在学习Python爬虫,感觉非常有意思,真的让生活可以方便很多. ...

随机推荐

  1. 自己封装的Windows7 64位旗舰版,微软官网上下载的Windows7原版镜像制作,绝对纯净版

    MSDN官网上下载的Windows7 64位 旗舰版原版镜像制作,绝对纯净版,无任何精简,不捆绑任何第三方软件.浏览器插件,不含任何木马.病毒等. 集成: 1.Office2010 2.DirectX ...

  2. jquery html属性和text属性的区别

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  3. Android源码编译make的错误处理

    android源码下载:官方下载 或参考android源码下载方式 Android编译版本: PLATFORM_VERSION=4.0.1(最新Android 4.0.1) OS 操作系统平台: Li ...

  4. Eclipse中Python开发环境搭建

    Eclipse中Python开发环境搭建  目 录  1.背景介绍 2.Python安装 3.插件PyDev安装 4.测试Demo演示 一.背景介绍 Eclipse是一款基于Java的可扩展开发平台. ...

  5. spring-stutrs求解答

    这里贴上applicationContext里的代码: <?xml version="1.0" encoding="UTF-8"?> <bea ...

  6. MongoDB索引

    1.目的 索引就是用来加速查询的.数据库索引与书籍的索引类似:有了索引就不需要翻遍整本书,数据库则可以直接在索引中查找,使得查找速度能提高几个数量级.在索引中找到条目以后,就可以直接跳转到目标文档的位 ...

  7. 熟悉vs2012IDE

    使用vs2012已经几个月了,深感对开发环境的学习有助于提高开发的效率.现将我的经验总结如下: 一.搜索 vs2012相比vs2010添加了正则搜索,极大的提高了代码的查询效率. 二.重构 同vs20 ...

  8. MFC--响应鼠标和键盘操作

    一个程序最重要的部分之一是对鼠标和键盘操作的响应. 一.  理解鼠标事件.之前对鼠标事件的认识仅仅局限于处理控件的单击与双击事件.但实际鼠标的操作包含很多.这里将以一个画图的小程序讲解对鼠标的响应. ...

  9. 火狐浏览器如何js关闭窗口的几种解决方法

    今天在项目上有一个页面要求在几秒后自动关闭,想着还比较简单,用window.close()就可以了,但是用IE/谷歌/火狐浏览器试了一下,发现IE可以,谷歌用网上的兼容方法也可以实现,但是火狐这里卡住 ...

  10. 搭建基于 STM32 和 rt-thread 的开发平台

    我们需要平台 如果说,SharePoint 的价值之一在于提供了几乎开箱即用的 innovation 环境,那么,智能设备的开发平台也一样.不必每次都从头开始,所以需要固定的工作室和开发平台作为创新的 ...