URP教务系统自动登录

这篇具有很好参考价值的文章主要介绍了URP教务系统自动登录。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

这篇博客是我对 hack 进学校教务系统的一个过程总结,详细代码已经放在GitHub上,需要的自取

URP教务系统自动登录脚本

验证码

打开网站 http://jwxs.hhu.edu.cn/ 直接重定向到了登录页面 http://jwxs.hhu.edu.cn/login

个人觉得这个教务系统界面还是比较好看的,因为大一刚来的时候是旧版的教务,UI还是2000年的风格。

我们面临的第一个问题就是验证码.

全自动区分计算机和人类的公开图灵测试(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),又称验证码,是一种区分用户是机器或人类的公共全自动程序。

获取验证码图片

打开浏览器的开发者工具,刷新页面,可以发现验证码的路径为

http://jwxs.hhu.edu.cn/img/captcha.jpg

URP教务系统自动登录

我们先写一小段代码把这张图片下载下来

import requests

prefix = 'http://jwxs.hhu.edu.cn/'
captcha_url = prefix + 'img/captcha.jpg'
src = 'captcha.jpg'

response = requests.get(captcha_url)
file = open(src, 'wb')
file.write(response.content)
file.close()

比如下面这张图片

URP教务系统自动登录

接下来就是进行文字识别了

识别验证码内容

这里我查阅资料发现需要使用 tesseract 这个OCR引擎,安装半天终于安装好了之后发现识别结果基本不太准,我又找到了一个名字很特殊的python库

ddddocr - 带带弟弟OCR通用验证码识别SDK免费开源版

我抱着玩一玩的心态安装了,并且尝试着识别了几张图片,发现效果还行

import ddddocr
import requests

prefix = 'http://jwxs.hhu.edu.cn/'
captcha_url = prefix + 'img/captcha.jpg'
src = 'captcha.jpg'

response = requests.get(captcha_url)
file = open(src, 'wb')
file.write(response.content)
file.close()

ocr = ddddocr.DdddOcr(show_ad=False)
with open(src, 'rb') as f:
    img_bytes = f.read()
res = ocr.classification(img_bytes)
print('captcha:', res)
>>> captcha: c65a

就它了!

在我尝试了很多张图片后,我发现由于图片中的干扰线,识别成功率其实不是很高,于是我就继续查阅资料,试图图片进行降噪处理。

图片降噪处理

在经历了多次失败之后,我总结了一下原因:

  1. 网上的解决方案并不一定适合所有种类的验证码,比如说有的验证码只是背景有噪点,或者有很多细线,而我们这个是一条和内容差不多的黑线,按照网上的一些方法降噪很可能连着内容本身也去掉了

  2. 仔细观察验证码,可以发现都是画面主题是红色,加上黑粗线,那我们只需要将图片中的黑色或者接近黑色的像素块改成白色不就行了?

URP教务系统自动登录

又是一轮新的尝试,最终发现下面这样处理效果最好

import ddddocr
import requests
from PIL import Image

prefix = 'http://jwxs.hhu.edu.cn/'
captcha_url = prefix + 'img/captcha.jpg'
src = 'captcha.jpg'
dst = 'captcha_p.png'


def process_data(src, dst):
    img = Image.open(src)
    w, h = img.size
    for x in range(w):
        for y in range(h):
            r, g, b = img.getpixel((x, y))
            low = 50
            up = 256
            if r == 0 and g == 0 and b == 0:
                img.putpixel((x, y), (255, 255, 255))
            if r in range(low) and g in range(low) and b in range(low):
                img.putpixel((x, y), (255, 255, 255))
            if r in range(low, up) and g in range(low, up) and b in range(low, up):
                img.putpixel((x, y), (255, 255, 255))
    img.save(dst)


if __name__ == "__main__":
    response = requests.get(captcha_url)
    file = open(src, 'wb')
    file.write(response.content)
    file.close()

    process_data(src, dst)

    ocr = ddddocr.DdddOcr(show_ad=False)
    with open(dst, 'rb') as f:
        img_bytes = f.read()
    res = ocr.classification(img_bytes)
    print('captcha:', res)

图片处理前后差别还是很大的

URP教务系统自动登录

URP教务系统自动登录

原理其实很简单,遍历所有像素点,如果该像素点的rgb分量都是0,就是黑色,改成白色,如果三个分量的值都在 0-50 或者 50-256 之间,也将这个像素改成白色。

这些终于是解决了验证码的问题,接下来才是正题:自动登录进教务

自动登录

如果我们什么都不输入,直接点击登录按钮时,我们会发现多了一个请求

POST http://jwxs.hhu.edu.cn/j_spring_security_check

URP教务系统自动登录

检查表单元素就可以发现是登录时提交给系统的信息,包括三个字段。

URP教务系统自动登录

这时我还没注意到没输密码时提交的密码其实不为空,这个点坑了我很久

是时候稍微整理一下代码了,我们来先写一个 Request 类,定义登录的方法

import requests
from bs4 import BeautifulSoup

USERNAME = 'xxxxxxxxxx'
PASSWORD = 'xxxxxxxxxx'

Host = 'jwxs.hhu.edu.cn'
prefix = 'http://jwxs.hhu.edu.cn/'
UserAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 ' \
            'Safari/537.36 '

login_url = prefix + 'login'
captcha_url = prefix + 'img/captcha.jpg'
post_url = prefix + 'j_spring_security_check'
index_url = prefix + 'index.jsp'


class Request(object):
    def __init__(self, username, password):
        self.username = username
        self.password = password
        self.session = requests.Session()
        self.headers = {
            'Host': Host,
            'User-Agent': UserAgent,
            'Referer': login_url,
        }
        self.cookies = self.session.cookies

    def captcha(self):
        src = 'captcha.jpg'
        dst = 'captcha_p.png'
        response = self.session.get(captcha_url)
        file = open(src, 'wb')
        file.write(response.content)
        file.close()
        res = captcha_code(src, dst)
        return res

    def login(self):
        post_data = {
            'j_username': self.username,
            'j_password': self.password,
            'j_captcha': self.captcha(),
        }
    
        self.session.post(post_url, post_data, headers=self.headers)
        response = self.session.get(index_url, headers=self.headers, cookies=self.session.cookies)
        soup = BeautifulSoup(response.text, 'lxml')
        name = soup.find('title').string
        if name == 'URP综合教务系统首页':
            print('login success')
            print('JSESSIONID:', self.session.cookies.get('JSESSIONID'))


if __name__ == "__main__":
    request = Request(USERNAME, PASSWORD)
    request.login()

我们来运行,奇怪,命令行并没有打印 login success

检查一下验证码识别结果?并没有问题

看一下HTML里的表单?都是对应上的

URP教务系统自动登录

学号对应 j_username,密码对应 j_password,验证码对应 j_captcha,不应该有问题啊

欸,不对,这个 hex_md5 是什么东西!!!

URP教务系统自动登录

于是我终于发现了不填密码提交表单中密码也是有内容的。

原来是在提交表单之前对密码字段进行了 md5 加密,寻找源文件发现了一个名为 md5.js 的文件

我在想,要不我把这个 js 脚本改写成 python 脚本?写了几行后放弃了,虽然二者都是动态语言,但是很多地方还是有点差异的,于是直接搜索 convert js to python,发现了 Js2Py 这个python库,相当方便

import js2py
# from md5 import *

if __name__ == "__main__":
    js2py.translate_file('md5.js', 'md5.py')
    # data = md5.hex_md5('12ibnsdkq1ed')
    # print(data)

第二次运行时取消所有注释,就可以看到测试结果了。

这时给我们的代码加上这个加密函数即可

from md5 import *

...
...

def login(self):
    post_data = {
        'j_username': self.username,
        'j_password': md5.hex_md5(self.password),
        'j_captcha': self.captcha(),
    }
   
    self.session.post(post_url, post_data, headers=self.headers)
    response = self.session.get(index_url, headers=self.headers, cookies=self.session.cookies)
    soup = BeautifulSoup(response.text, 'lxml')
    name = soup.find('title').string
    if name == 'URP综合教务系统首页':
        print('login success')
        print('JSESSIONID:', self.session.cookies.get('JSESSIONID'))

这时可以顺利进入系统了

captcha: xxxx
login success
JSESSIONID: abcMTh7Thb9p4ef4DZ2my

爬取需要的数据

这不是线下上课了嘛,上完课想找个空教室自习成了个不是那么容易的事,除了自己找还可以上教务查询,但是每次登录教务还要输验证码,登录状态还会很快失效,就把这件事变成了简单但很重复的事情。如果我都能自动登录教务了,那空闲教室信息岂不是有手就能爬?说干就干!

首先定位到空闲教室查询主页

随便点击一个教学楼,可以发现浏览器向 http://jwxs.hhu.edu.cn/student/teachingResources/freeClassroom/today 发送了一个 POST 请求,请求头里的 Content_typeapplication/x-www-form-urlencoded,这个得划下来,等会儿要靠

URP教务系统自动登录

查看表单会发现,有两个信息,应该是教学楼编号和校区号

URP教务系统自动登录

我们往下看可以看到还多出来一个 queryCodeTeaBuildingList ,点击进去发现确实如此

URP教务系统自动登录

江宁校区的勤学楼的编号是 2_11

如果我们试图直接获取当前页面也就是 http://jwxs.hhu.edu.cn/student/teachingResources/freeClassroom/today 的内容会发生什么?

答案当然是得不到我们想要的结果,原因在于 application/x-www-form-urlencoded

application/x-www-form-urlencoded: 数据被编码成以 ‘&’ 分隔的键 - 值对,同时以 ‘=’ 分隔键和值。非字母或数字的字符会被 percent-encoding: 这也就是为什么这种类型不支持二进制数据 (应使用 multipart/form-data 代替).

查看网页源代码会发现,这里使用了动态渲染技术,简单说就是 JSP

JSP(全称Jakarta Server Pages,曾称为JavaServer Pages)是由Sun Microsystems公司主导创建的一种动态网页技术标准。JSP部署于网络服务器上,可以响应客户端发送的请求,并根据请求内容动态地生成HTML、XML或其他格式文档的Web网页,然后返回给请求者。JSP技术以Java语言作为脚本语言,为用户的HTTP请求提供服务,并能与服务器上的其它Java程序共同处理复杂的业务需求。

怎么说呢,现在基本不用这种技术了,现在可以说是前后端分离的时代,但是教务这种比较有年头的系统不可避免还在用这些技术,而且教务这种管理系统的复杂度是相当高的,想改动也很不容易。

那我们怎么办呢,其实还有办法,我们注意看自定义选项

URP教务系统自动登录

我们有很多选择来进行查询,而查询结果在下面的二位表格里,不妨直接点一下搜索

可以看到多出来的 search

URP教务系统自动登录

注意看请求头和效应头里的 Content-Type,服务器返回了JSON格式的数据,如果做过前后端分离的项目对这个是不是很熟悉?

我猜测现在的教务系统不全是 JSP,也有这种部分前后端分离的接口。

URP教务系统自动登录

对与前后端的数据应该很好解析,在贴代码之前我们先来分析一下表单元素

URP教务系统自动登录

  • weeks - 周数
  • jslxdm - 教室类型
  • codeCampusListNumber - 校区编号
  • teaNum - 教学楼编号
  • wSection - 星期/节次
  • pageNum - 页数
  • pageSize - 每页数量

知道了每个字段的含义,再加上查询得到的教学楼编号等等,即可查询到某天某节某个教学楼的空闲教室情况,这里直接贴出代码。

...
...

def search_free_classroom(self, query_param):
        headers = {
            'Host': Host,
            'User-Agent': UserAgent,
            'Referer': query_refer_url,
            'X-Requested-With': 'XMLHttpRequest',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        }
        response = self.session.post(query_url, data=query_param, headers=headers, cookies=self.session.cookies)
        data = response.json()[0]['records']
        logging.debug('free classrooms:', '(week', query_param['weeks'], ')', '(section', query_param['wSection'], ')')
        sets = []
        for i in range(len(data)):
            val = data[i]['classroomName']
            sets.append(val)
        logging.debug(sets)
        return sets


if __name__ == "__main__":
    request = Request(USERNAME, PASSWORD)
    request.login()
    param = {
        'weeks': 3,
        'jslxdm': 1,
        'codeCampusListNumber': 1,
        'teaNum': 14,
        'wSection': 4/4,
        'pageNum': 1,
        'pageSize': 10,
    }
    request.search_free_classroom(param)

基本想法完成了,但是,比较困扰我的一点是,查询到的数据该以什么样的方式存储起来,这一点可能还需要我好好想想,或许会写个接口来传输数据,然后写个App方便查询?还不太确定。

以上。文章来源地址https://www.toymoban.com/news/detail-405439.html

到了这里,关于URP教务系统自动登录的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 高校教务系统登录页面JS分析——重庆交通大学

    本文将介绍高校教务系统的密码加密逻辑以及使用JavaScript进行逆向分析的过程。通过本文,你将了解到密码加密的基本概念、常用加密算法以及如何通过逆向分析来破解密码。 本文仅供交流学习,勿用于非法用途。 密码加密是一种保护信息安全的技术手段,它通过将明文(

    2024年02月07日
    浏览(36)
  • centos停止更新?这篇博客教会你CentOS 7转化系统为阿里龙蜥Anolis OS 7

    目录 前言 一.centos停止维护 1.迁移背景 2.CentOS停止维护的影响 二.正式迁移 1.注意事项 2.部署迁移工具 1.下载迁移工具软件源 2.安装epel源   3.安装依赖(可根据安装工具时是否报错选择安装) 4.安装迁移工具 5.执行迁移 6.迁移后验证 随着技术的飞速发展,操作系统也日新月

    2024年01月18日
    浏览(39)
  • 个人博客系统 -- 登录页面添加图片验证码

    目录 1. 功能展示 2. 前段代码 3. 后端代码 在登录页面添加验证码登录 1. 检测到没有输入验证码或者输入的验证码错误时,进行弹窗提示.并且刷新当前验证码图片 2. 点击验证码进行刷新   1. 添加验证码标签,在密码的下面,在login.html进行修改 主要改动如下: 2. 在提交的函数中加

    2024年02月15日
    浏览(45)
  • 入门孪生网络Siamese Network,我将会分几个博客来逐步阐述我对孪生网络的理解和应用---初步介绍0

    孪生网络的英文名字是 “Siamese Network”,其得名来源于 1980 年代的一部电影 “The Man with One Red Shoe”,其中两个孪生兄弟被称为Siamese twins,因为其外表基本相同。由此,孪生网络的设计也是基于两个或多个结构相同的子网络。 孪生网络(Siamese Network)是一类神经网络结构,

    2024年02月08日
    浏览(28)
  • 博客系统后端设计(五) - 实现登录页面功能

    这里约定 请求 是一个 POST 请求,路径是 /login ,使用的是以下的格式: usernam=zhangsanpassword=123 响应是 HTTP/1.1 302 ,因为在成功登录之后,会直接跳转到列表页, 因此此时的 Location 是 blog.list.html 。 此时的响应要求是 302,因此要使用 form 表单才可以进行页面的跳转; 如果是

    2024年02月05日
    浏览(36)
  • 【个人博客系统网站】我的博客列表页 · 增删改我的博文 · 退出登录 · 博客详情页 · 多线程应用

    【JavaEE】进阶 · 个人博客系统(4) 用户在网页中编写标题和正文,点击提交,选择 输入摘要 取消,继续编写文章 提交成功后,选择 继续写文章 返回“我的博客列表页” 1.1 约定前后端交互接口 后端: /art/publish 将前端传递过来的数据保存到数据库 返回受影响行数 前端:

    2024年02月10日
    浏览(30)
  • 博客系统之自动化测试

    背景: 针对个人博客项目进行测试,个人博客主要由四个页面构成:登录页、列表页、详情页和编辑页,主要功能包括:用户登录功能、发布博客功能、查看文章详情功能、查看文章列表功能、删除文章功能、退出功能。对于个人博客的测试主要就是针对主要功能进行测试,

    2024年02月12日
    浏览(29)
  • 【自动化项目实战】博客系统

    目录 1.博客自动化测试用例 2.准备工作  3.将手工测试用例转化为自动化测试用例 3.1 初始化动作 3.2 登录 3.3 博客列表博客数量 3.4 查看全文 3.5 写博客发表博客 3.6 删除 3.7 注销 4.总代码 🌈这节文章我们讲解一个实战项目——博客系统。首先我们需要 熟悉项目、针对核心流程

    2024年02月07日
    浏览(47)
  • 博客系统实现自动化测试

    目录 一、设计博客系统的测试用例 二、利用测试用例进行测试  测试登录页面 界面测试  功能测试 测试博客列表页  界面测试 功能测试  测试博客详情页  界面测试 功能测试 博客编辑页测试 界面测试 功能测试  测试的文件放在maven项目的test文件夹下,需要在之前的mav

    2024年02月02日
    浏览(22)
  • 自动化项目实战 [个人博客系统]

    效验第一篇博客 不是 “自动化测试” 退出到登录页面,用户名密码为空

    2024年02月08日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包