python爬虫之 正方教务管理系统查询成绩

目录

         前言

0. 依赖及代码头:

1. 登录

1) 验证码

2)登录请求构造

2. 跳转到成绩界面获取成绩

3. 输出成绩

4.整体代码


前言

以下的所有代码都基于python3

最近学习网络爬虫...加上我们学校的教务系统经常因为各种奇怪的原因没有办法读取界面啥啥啥的....所以这里准备写一个脚本挂到服务器上,之后增加到我的博客界面....方便所有人查询自己的成绩以及课表,课表的话爬取比较简单,因为跳转次数较少,方式也大同小异,所以这里只给出爬取成绩的具体思路

0. 依赖及代码头:

  1. Beautiful库,解析网页
  2. PrettyTable库,格式化输出
  3. PIL,抓取验证码并显示
  4. urllib库,http请求库

以下是代码头,这里我们需要构造一个opener来模拟在线连续访问

import re
import urllib.request
import urllib.parse
import http.cookiejar
import bs4
import getpass
import pickle
import os
import platform
import subprocess
from bs4 import BeautifulSoup
from prettytable import PrettyTable
from PIL import Image
from PIL import ImageEnhance
import pytesseract

#准备Cookie和opener,因为cookie存于opener中,所以以下所有网页操作全部要基于同一个opener
cookie = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))

1. 登录

首先我们看到登录界面,需要提供三个内容{用户名密码验证码},用户名密码都是我们已知的,那么我们需要先解决第一个问题,就是这个验证码

1) 验证码

我们打开F12开发者工具,打开network,然后点击验证码刷新出一张新的验证码,然后就可以看到验证码的来源地址是http://zfxk.zjtcm.net/CheckCode.aspx

2)登录请求构造

我们先登录一次,然后同样的在network中找到我们的请求界面中找到我们登录时提交的表单

这里需要四个内容,{__VIEWSTATE,txtUserName,TextBox2,txtSecretCode},当然这里的RadioButtonList1也是需要填写的,这里显示不出来是因为这是中文表单,内容是“学生”,也就是我们登录时需要勾选的登录方式

__VIEWSTATE是为了防止攻击增加的内容,这个东西我们可以在登录前的界面中找到

txtUserName就是用户名,TextBox2中的就是密码,txtSecretCode中就是验证码

那么现在我们已经找齐了登录所需要的所有内容,现在只需要一个个组合成请求即可

用户名密码我们当然是需要输入的

username=input("输入用户名: ")
password=input("输入密码 ")

验证码直接去验证码链接中保存下图片,然后手动输入,当然也可以增加验证码识别功能....正方的验证码都是比较简单的基础验证码...稍微处理一下就可以达到较高的识别率,当然这里就不作赘述

res = opener.open('http://zfxk.zjtcm.net/checkcode.aspx').read()
with open(r'D:\code.jpg','wb') as file:
file.write(res)
im = Image.open(r'D:\code.jpg')
im.show()
vcode = input('请输入验证码:')
im.close()

以及获取__VIEWSTATE

response = urllib.request.urlopen('http://zfxk.zjtcm.net/')
html = response.read().decode('gb2312')
viewstate = re.search('<input type="hidden" name="__VIEWSTATE" value="(.+?)"',html)

在获取所有内容后,我们组成登录所需要的请求头

params = {
            '__VIEWSTATE':viewstate.group(1)
            'txtUserName' : username,
            'Textbox1' : '',
            'Textbox2': password,
            'txtSecretCode':vcode
            'RadioButtonList1':'学生',
            'Button1' : '',
            'lbLanguage':'',
            'hidPdrs':'',
            'hidsc':'',
        }

接下来我们使用这个表单请求登录

data = urllib.parse.urlencode(params).encode('gb2312')
response = opener.open(loginurl,data)

就可以完成登录了

以下是完整的登录代码

username=input("输入用户名: ")
password=input("输入密码 ")

while True:
    params = {
            'txtUserName' : username,
            'Textbox1' : '',
            'Textbox2': password,
            'RadioButtonList1':'学生',
            'Button1' : '',
            'lbLanguage':'',
            'hidPdrs':'',
            'hidsc':'',
        }
    #获取验证码
    res = opener.open('http://zfxk.zjtcm.net/checkcode.aspx').read()
    with open(r'D:\code.jpg','wb') as file:
        file.write(res)
    im = Image.open(r'D:\code.jpg')
    im.show()
    vcode = input('请输入验证码:')
    im.close()
    params['txtSecretCode'] = vcode
    #获取ViewState
    response = urllib.request.urlopen('http://zfxk.zjtcm.net/')
    html = response.read().decode('gb2312')
    viewstate = re.search('<input type="hidden" name="__VIEWSTATE" value="(.+?)"',html)
    params['__VIEWSTATE'] = viewstate.group(1)

    #尝试登陆
    loginurl = 'http://zfxk.zjtcm.net/default2.aspx'
    data = urllib.parse.urlencode(params).encode('gb2312')
    response = opener.open(loginurl,data)
    if response.geturl() != 'http://zfxk.zjtcm.net/default2.aspx':
        #获取学生姓名,之后需要使用
        catch='<span id="xhxm">(.*?)</span>'
        tmpname=re.search(catch,response.read().decode('gb2312'))
        name=tmpname.group(1)
        name=name[:-2]
        break

print(name)

2. 跳转到成绩界面获取成绩

同样的在network上找到查询成绩的直接地址,可以看到是

http://zfxk.zjtcm.net/xscj_gc.aspx?xh=(.?)&xm=(.?)&gnmkdm=N121605

xh后面是自己的学号,即登陆的usernamexm则是登录后抓取的姓名在网页编码gb2312下的转义

当然这里有一点特殊的地方,如果我们直接在地址中输入我们构造出的查询界面的链接,会出现302跳转,在python下可能会报错

当然这也是一定程度上的网站防护措施

那么解决这一问题也很简单,我们可以猜想为什么我们正常点击可以跳转到页面,而直接输入链接却不行,最简单的猜想就是,在传递的表单中我们需要给出我们是从哪个界面跳转过来的,只有某些特定界面的跳转才被允许,并且查看一下network中的表头我们可以发现一项名为Referer

所以这一项也是非常重要的...需要同时构造在表头中,所以在查询成绩的这一步中,我们不止需要构造请求表单data,还需要构造表头headers

构造表单时,当然我们可以发现还是需要__VIEWSTATE这一项的,这一项当然可能会发生改变,所以我们去登录成功后的界面获取这一项的内容

req = urllib.request.Request(url)
print(url)
req.add_header('Referer','http://zfxk.zjtcm.net/xs_main.aspx?xh='+username )
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')
response = opener.open(req)
html = response.read().decode('gb2312')
# print(html)
viewstate = re.search('<input type="hidden" name="__VIEWSTATE" value="(.+?)"',html)

然后按上面的方式构造表头

params = {
    'ddlXN':'',
    'ddlXQ':'',
    'Button2':'在校学习成绩',
}
params['__VIEWSTATE'] = viewstate.group(1)

构造完dataheaders

我们就可以访问查询成绩的界面了

req = urllib.request.Request(url,urllib.parse.urlencode(params).encode('gb2312'))
req.add_header('Referer','http://zfxk.zjtcm.net/default2.aspx')
req.add_header('Origin','http://zfxk.zjtcm.net/')
response = opener.open(req)
soup = BeautifulSoup(response.read().decode('gb2312'),'html.parser')
html = soup.find('table',class_='datelist')

这里的response就是我们需要的成绩页面,然后就是怎么从成绩页面获取我们需要的内容了,这里我们使用BeautifulSoup这个库,直接find所有成绩标签

3. 输出成绩

这里使用prettytable库来格式化输出表单,当然这里也可以保存到excel中或者各种各样个人喜欢的方式.....


print('你的所有成绩如下:')
#指定要输出的列,原网页的表格列下标从0开始
outColumn = [1,2,3,4,6,7,8]
#用于标记是否是遍历第一行
flag = True

for each in html:
    columnCounter = 0
    column = []
    if(type(each) == bs4.element.NavigableString):
        pass
    else:
        #遍历列
        for item in each.contents:
            if(item != '\n'):
                if columnCounter in outColumn:
                    #要使用str转换,不然陷入copy与deepcopy的无限递归
                    column.append(str(item.contents[0]).strip())
                columnCounter += 1
        if flag:
            table = PrettyTable(column)
            flag = False
        else:
            table.add_row(column)
print(table)

 

以上就是简单的爬取正方教务系统在校成绩的代码

4.整体代码

import re
import urllib.request
import urllib.parse
import http.cookiejar
import bs4
import getpass
import pickle
import os
import platform
import subprocess
from bs4 import BeautifulSoup
from prettytable import PrettyTable
from PIL import Image
from PIL import ImageEnhance
import pytesseract

#准备Cookie和opener,因为cookie存于opener中,所以以下所有网页操作全部要基于同一个opener
cookie = http.cookiejar.CookieJar()
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookie))

username=input("输入用户名: ")
password=input("输入密码 ")

while True:
    params = {
            'txtUserName' : username,
            'Textbox1' : '',
            'Textbox2': password,
            'RadioButtonList1':'学生',
            'Button1' : '',
            'lbLanguage':'',
            'hidPdrs':'',
            'hidsc':'',
        }
    #获取验证码
    res = opener.open('http://zfxk.zjtcm.net/checkcode.aspx').read()
    with open(r'D:\code.jpg','wb') as file:
        file.write(res)
    im = Image.open(r'D:\code.jpg')
    im.show()
    vcode = input('请输入验证码:')
    im.close()
    params['txtSecretCode'] = vcode
    #获取ViewState
    response = urllib.request.urlopen('http://zfxk.zjtcm.net/')
    html = response.read().decode('gb2312')
    viewstate = re.search('<input type="hidden" name="__VIEWSTATE" value="(.+?)"',html)
    params['__VIEWSTATE'] = viewstate.group(1)

    #尝试登陆
    loginurl = 'http://zfxk.zjtcm.net/default2.aspx'
    data = urllib.parse.urlencode(params).encode('gb2312')
    response = opener.open(loginurl,data)
    if response.geturl() != 'http://zfxk.zjtcm.net/default2.aspx':
        #获取学生姓名,之后需要使用
        catch='<span id="xhxm">(.*?)</span>'
        tmpname=re.search(catch,response.read().decode('gb2312'))
        name=tmpname.group(1)
        name=name[:-2]
        break

print(name)

#构造url
url = ''.join([
        'http://zfxk.zjtcm.net/xscj_gc.aspx',
        '?xh=',
         username,
        '&xm=',
        urllib.parse.quote(name),
        '&gnmkdm=N121605',
    ])
#构建查询全部成绩表单
params = {
    'ddlXN':'',
    'ddlXQ':'',
    'Button2':'在校学习成绩',
}
#构造Request对象,填入Header,防止302跳转,获取新的View_State
req = urllib.request.Request(url)
print(url)
req.add_header('Referer','http://zfxk.zjtcm.net/xs_main.aspx?xh='+username )
req.add_header('User-Agent','Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36')

response = opener.open(req)
html = response.read().decode('gb2312')
# print(html)
viewstate = re.search('<input type="hidden" name="__VIEWSTATE" value="(.+?)"',html)
params['__VIEWSTATE'] = viewstate.group(1)
#查询所有成绩
req = urllib.request.Request(url,urllib.parse.urlencode(params).encode('gb2312'))
req.add_header('Referer','http://zfxk.zjtcm.net/default2.aspx')
req.add_header('Origin','http://zfxk.zjtcm.net/')
response = opener.open(req)
soup = BeautifulSoup(response.read().decode('gb2312'),'html.parser')
html = soup.find('table',class_='datelist')

print('你的所有成绩如下:')
#指定要输出的列,原网页的表格列下标从0开始
outColumn = [1,2,3,4,6,7,8]
#用于标记是否是遍历第一行
flag = True

for each in html:
    columnCounter = 0
    column = []
    if(type(each) == bs4.element.NavigableString):
        pass
    else:
        #遍历列
        for item in each.contents:
            if(item != '\n'):
                if columnCounter in outColumn:
                    #要使用str转换,不然陷入copy与deepcopy的无限递归
                    column.append(str(item.contents[0]).strip())
                columnCounter += 1
        if flag:
            table = PrettyTable(column)
            flag = False
        else:
            table.add_row(column)
print(table)

 

当然这份代码没有增加验证码识别以及美化成绩界面,之后可能会为了方便考虑将这份代码连接html后写入我的博客中...这样可以方便所有本校同学在各个地方查询成绩以及课表....

Java学校教务管理系统源码带微信小程序 开发语言 : JAVA 数据库 : MySQL 开发工具 : IDEA 源码类型 : WebForm 注意:不带技术支持,有帮助文件,虚拟商品,发货不退,看好再拍。 运行环境:jdk8+mysql5.7+IntelliJ IDEA+maven  技术:springboot+mybatis+layui+shiro+jquery 教务管理系统是一个基于网络的在线管理平台 , 帮助学校管理教务系统,用一个帐号解决学校教务教学管理, 灵活的定制符合学校自己实际情况的教务系统。 功能介绍 教务管理系统分为微信小程序和3个子系统,3个子系统分别是管理员系统、教师系统和学生系统,分别对应 拥有不同权限的角色:管理员、教师和学生; (1)管理员系统:管理员可以管理课程、管理教师、管理学生、发布校园公告、校建管理、教评问题管理、分配权限等功能; (2)教师系统:教师登录教师系统,可以查看自己所教授的课程信息、查看某门课程所选学生信息、给学生打分以及修改自己的登录密码; (3)学生系统:学生根据姓名和密码登录自己的学生系统,可以查看所有的课程信息、查看已选课程、查看已修课程、选课以及退课等操作。 (4)微信小程序:主要实现了学生的成绩查询、学生信息查询、网上教评、学生选课、退课等功能。 模块说明 4.1、小程序模块   4.1.1、小程序登录:调用在idea封装的登录接口;                4.1.2、小程序查看成绩:用js通过学生入学时间来判断学期,然后按学期进行条件查询;                                  4.1.3、小程序退选课程:先查学生所选的课程,以及是否没成绩,如果没成绩,可以退课; 4.1.4、小程序我的信息:根据学生的学号来查询学生自身的信息; 4.1.5、微信小程序校园公告:查询出校园要发布的公告,显示出来。 微信小程序课表查询:根据登录学生的学号和学生所在的班级,查询出他所选的课程以及课程上课地点和上课时间。 4.1.6、微信小程序选课:查询出学生所有可以选的网上课程和课程的所有信息,显示出来,点击选择按钮进行选择, 如果人数没满,则成为自己的课程。 4.1.7、微信小程序掌上教评:根据所登录学生的学号和班级查询出所教他所有课程的教师,只能对这些教师进行教评 。教评获得的分数将插入对应教师的成绩和教评记录表。 4.2、PC端模块 4.2.1、权限管理:查询所有权限,可以添加一个新的权限,拥有不同权限资源,也可以通过权限的id修改权限所拥有的不同权限资源。 4.2.2、角色管理:查询所有角色信息,可以添加一个新的角色,查询所有的权限,返回list集合,遍历在页面的权限分配上,分配不同权限,也可以修改角色所拥有的权限。 4.2.3、用户管理:查询所有用户信息,可以添加一个新用户,查询所有的角色,返回list集合,遍历在页面的角色分配上,不同用户分配不同角色,也可以修改该用户的角色。 4.2.4、学生成绩查询:管理员查询所有学生,通过系部、专业、年级、班级、学期进行分类查询。 4.2.5、教师成绩查询:管理员查询教评总成绩和教评总人数,通过查询计算,获得所需要的教师成绩。 4.2.6、教师查询学生成绩:通过教师登录工号,查询教师所教的班级及学生的成绩。 4.2.7、新闻发布:学校的新闻以及公告可以通过此功能实现,通常是教学方面的新闻,发布时可自定义发布人。新闻的编辑采用目前最为流行的笔记记录语言:Markdown,可直接使用该语言进行图文编排。发布后即可在官网首页看到。 4.2.8、新闻管理:新闻管理主要用来管理已经发布的新闻,包括编辑和删除操作,通常用来修改错别字或修改发布部门(人)。 4.2.9、学校建设:主要建设系部、专业、年级、班级,并且必须按照该顺序进行建设。 4.2.10、学生教评:学生教评是学生对教师一个学期的评价,给教师评分。 4.2.11、教师授课:实现对每个教师所授课程的管理,保证了每个教师的课不冲突、不重复。 4.2.12、学生信息查询、修改:管理员可对所有学生信息进行查询以及修改,教师可对所教学生信息进行查询及修改。 4.2.13、教师信息查询、修改:管理员可对所有教师信息进行查询修改。 4.2.14、学生退学情况查询:对已退学的学生进行查询,可查看学生信息、退学时间及退学原因等。 4.2.15、学生、教师录入:管理员可以进行教师录入和学生录入,教师无法录入教师,只能录入学生。 4.2.16、学生个人成绩查询:学生登录账号,根据学号查询该生所有成绩。 4.2.17、学生选课管理:查询出所有学生和该学生所选的课程,可以搜索单个学生或者有下拉框进行条
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值