基于Python 3.11.0版本模拟登录并爬取西安理工大学正方教务系统的学分绩点并计算

该博客介绍了如何使用Python 3.11.0模拟登录西安理工大学的正方教务系统,爬取学分绩点信息,并实现绩点计算器功能。博主详细讲解了环境搭建、模拟登录、爬取数据的过程,以及绩点计算的两个主要功能:计算预期总绩点和分析已选课程。文中提供了完整的代码示例。
摘要由CSDN通过智能技术生成

目录

使用软件以及运行环境

对于环境的搭建

代码思路

需要导入的包

模拟登录

爬取数据

绩点计算器

功能一

功能二

完整代码

使用软件以及运行环境

win10系统,Vs Code软件,Python 3.11.0环境下。

对于环境的搭建

知乎有一个帖子叫做:爬虫入门到精通-环境的搭建

这个帖子很详细,可以完整地搭建好python环境

Vs Code中,我下载的扩展如下,大家可以悉数下载:

 对于每个扩展有什么用处,大家可以去搜一下。

ctrl+shift+p打开搜索栏,搜索lauch.json来配置python的调试

我的lauch.json内容如下

{
    // 使用 IntelliSense 了解相关属性。 
    // 悬停以查看现有属性的描述。
    // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python: currenfile",
            "type": "python",
            "request": "launch",
            "program":"${file}",
            "console":"integratedTerminal"
        }
    ]
}

接下来的配置不多赘述,F5调试,暂停可单步调试。

代码思路

如题所述,首先要实现爬数据,然后将数据整理,最后作处理,并用一些方法供用户使用。

需要导入的包

import os
import bs4
import urllib
import requests

模拟登录

要爬取数据,就得模拟登录,西安理工大学旧教务系统使用的是正方教务系统,模拟登录则首先要看一看西安理工大学旧教务系统的主页

 可以看到登录界面就是要输入用户名、密码、验证码以及选择用户类型,这里我们默认是学生类型不需要修改,我们先用谷歌浏览器的f12打开开发者模式,然后尝试一下登录

 可以看到network这里出现了一堆东西,我们点开第一个jsp看看

可以看到这里的response headers,将它保存下来,用作登录时所需要的headers,代码中如下

headers = {  # 设定登录时的headers
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Content-Length": "209",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "xfz.xaut.edu.cn",
    "Origin": "http://xfz.xaut.edu.cn",
    "Referer": "http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/default2.aspx",
    "Upgrade-Insecure-Requests": "1"
}

点击payload我们可以看到传递过去的数据,点击红色箭头位置,将文字转为解码后的,可以看到信息如下,我们需要的用户名、密码、验证码都有,还有一个隐藏的输入_VIEWSTATE,我们暂且不管他是干什么的,底下的buttonlist是一个固定值,可以验证一下

 

 用户名和密码我们可以自行输入,而验证码需要获取到,这里我们查看一下验证码的url

右键验证码,检查可以发现它的url在这里,我们将它和主页url都保存下来

# 定义登录页面链接和验证码链接
url = 'http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/default2.aspx'
imgUrl = 'http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/CheckCode.aspx'

验证码的headers和主页的相同,可以共用,同学们可以自行测试,接下来就是爬取验证码

def get_post_data(url, username, password):  # 定义获取验证码、并返回登录所需的data的函数
    re = s.get(url)  # 从登录页面获取response给变量re
    # re.text是登录页面的html,以lxml格式用bs4的BeautifulShop方法传递给变量soup
    soup = bs4.BeautifulSoup(re.text, 'lxml')
    __VIEWSTATE = soup.find('input', attrs={'name': '__VIEWSTATE'})[
        'value']  # 获取隐藏input中的值:_VIEWSTATE 用于登录时的data
    imgresponse = s.get(imgUrl, stream=True)  # 从验证码页面得到response
    image = imgresponse.content  # 用response.content调用验证码 即验证码页面内容
    DstDir = os.getcwd()+"\\"  # 保存到当前目录下
    print("保存验证码到:"+DstDir+"code.jpg"+"\n")
    try:  # 尝试是否能读写
        with open(DstDir+"code.jpg", "wb") as jpg:
            jpg.write(image)
    except IOError:
        print("IO Error\n")
    finally:
        jpg.close
    ycode = input("请输入验证码:")
    data = {
        'txtUserName': username,
        'TextBox1': '',
        'TextBox2': password,
        'txtSecretCode': ycode,
        '__VIEWSTATE': __VIEWSTATE,
        'RadioButtonList1': '%D1%A7%C9%FA',
        "Button1": "",
        "lbLanguage": "",
        "hidPdrs": "",
        "hidsc": ""
    }
    return data

此处的s在全局变量的定义如下

s = requests.session()  # 获取一个session给变量s

此处首先获取到登录界面的隐藏_VIEWSTATE的值,然后保存验证码到本地目录下查看即可,data数据是用来登录的,保存并作为返回值

有了headers和data就可以模拟登录了,登录函数如下,接下来后面的函数都是登录函数中包括到的

def login(url, data):  # 定义登录函数
    global username
    r = s.post(url, headers=headers, data=data)
    if judge(r.text) == 1:
        soup = bs4.BeautifulSoup(r.text, 'lxml')
        name_code = soup.find(name='span', attrs={'id': 'xhxm'})
        name = urllib.parse.quote_plus(  # name为登录成功后的网页源码解析后获得的姓名的gb2312解码
            str(name_code.string[11:14]).encode('gb2312'))
        b = str(name_code).find('>')
        a = str(name_code).find('</span>')
        print('❀'+(str(name_code)[b+1:a] + '你好').center(88, '-')+'❀')
        kburl = get_headers(username, name)  # 获取成绩页面链接
        data = get_cj_data(kburl)  # 获取访问成绩页面所需data
        cjLoading(kburl, headers_code, data)  # 获取成绩
    else:
        print(judge(r.text))
        print("请重新登录")
        main()

这里的judge函数是用来判断是否登录成功的,具体内容为

def judge(html):  # 判断登录的接口
    soup_judge = bs4.BeautifulSoup(html, 'html.parser')
    script = soup_judge.find_all('script')[0].text
    if script != "":
        return "登录错误"
    else:
        return 1

爬取数据

用session的post方法提交数据,获得的response对象保存在r变量中,登录成功后得到姓名的gb2312编码,传递给get_headers函数,这个函数用来返回查询成绩界面所需要的url和referer,get_headers的具体内容如下

def get_headers(username, name):  # 定义函数,用以获取成绩的headers中的refer,并返回查询成绩所在的链接地址,此步在登录之后
    headers_code['Referer'] = "http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/xscj_gc" + \
        ".aspx?xh=" + username + "&xm="+name+"&gnmkdm=N121603"
    kburl = "http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/xscj_gc" + \
        ".aspx?xh=" + username + "&xm="+name+"&gnmkdm=N121603"
    return kburl

这个格式如何得到的呢?我们点击登陆成功后的学分制主页的查询所有成绩,选择相应的jsp可以看到

 url链接和referer格式如上图,这个referer很重要,没有的话会被弹出

headers_code在全局被定义为

headers_code = {  # 设定查询绩点时的headers
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
    "Referer": "",
    "Host": "xfz.xaut.edu.cn",
    "Origin": "http://xfz.xaut.edu.cn",
    "Upgrade-Insecure-Requests": "1"
}

有了url和headers,还需要data,get_cj_data函数被定义为

def get_cj_data(kburl):  # 获得查询成绩的data,其中__VIEWSTATE,需要先用get请求获得源码后在通过解析获得,btn_xn的值为学年成绩的gb2312解码
    response = s.get(kburl, headers=headers_code)
    html = response.content.decode('gb2312')  # 获取源码并解析
    soup = bs4.BeautifulSoup(html, 'lxml')
    __VIEWSTATE = soup.find('input', attrs={'name': '__VIEWSTATE'})['value']
    data = {
        '__VIEWSTATE': __VIEWSTATE,
        'ddlXN': '',
        'ddlXQ': '',
        'Button5': '%B0%B4%D1%A7%C4%EA%B2%E9%D1%AF'
    }
    return data

需要的data依然可以在payload中看到

 接下来成功访问到成绩页面后,就可以获取成绩了,获取成绩的函数如下

def cjLoading(kburl, headers_code, data):  # 学生成绩的获取
    global s, totalGpa, totalCredit
    response = s.post(kburl, headers=headers_code, data=data)  # 加载成绩查询页面
    html = response.content.decode('gb2312', errors='ignore')  # 获取页面的html,忽略错误
    soup1 = bs4.BeautifulSoup(html, 'lxml')
    xfjdzh = soup1.find('span', attrs={'id': 'xfjdzh'})  # 找到id为xfjdzh的span标签
    a = str(xfjdzh).find('</b>')
    b = str(xfjdzh).find('<b>')
    totalGpa = float(str(xfjdzh)[b+10:a])  # 提取出学分绩点总和数据,用float形式保存
    # 找到第一个属性符合的td标签,其中保存着学分总和
    xftj = soup1.find('td', attrs={'valign': 'top', 'colspan': '2'})
    b = str(xftj).find('<td>', str(xftj).find('<b>')+18)
    a = str(xftj).find(
        '</td>', str(xftj).find('</td>', str(xftj).find('<b>')+18)+1)
    totalCredit = float(str(xftj)[b+4:a])  # 提取出学分总和,用float形式保存

为什么是这种格式呢?我们检查成绩页面的标签可以看到

 

大家可以去搜一下获取成绩时用到的方法例如str.find()和soup.find()都是干什么用的,帮助你们快速理解 

这下我们就爬到了总学分绩点和总学分数据,并分别保存到了全局变量totalGpa和totalCredit中,至此,登录并爬取数据任务完成,总共的代码如下

import os
import bs4
import urllib
import requests


totalGpa = 0  # 从网上爬下的总学分绩点和总学分 初值为0
totalCredit = 0

username = ''  # 预设学号密码,方便演示调试
password = 

s = requests.session()  # 获取一个session给变量s

# 定义登录页面链接和验证码链接
url = 'http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/default2.aspx'
imgUrl = 'http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/CheckCode.aspx'

headers = {  # 设定登录时的headers
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Content-Length": "209",
    "Content-Type": "application/x-www-form-urlencoded",
    "Host": "xfz.xaut.edu.cn",
    "Origin": "http://xfz.xaut.edu.cn",
    "Referer": "http://xfz.xaut.edu.cn/(ldvbtr55xj1noy45ran0ug55)/default2.aspx",
    "Upgrade-Insecure-Requests": "1"
}

headers_code = {  # 设定查询绩点时的headers
    "Accept-Encoding": "gzip, deflate",
    "Accept-Language
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值