Bootstrap

NEU健康上报脚本解析教程

一、概述

python脚本不是我写的,源项项目地址(感谢作者的开源):
链接: https://github.com/Bmaili/NEU_health_daka

需要技术,简单的抓包,python的 re request模块

源项目是一个项目,有配置文件部分、发送邮件部分,我这里做了修改只保留了核心程序run.py部分,并且temperatureDaka函数不调用

import re
import time
import requests
#import sendMsg
#import config
#运行命令,cmd下
#python ./run.py 学号 校园网密码

import sys


class daka():
    def __init__(self):
        #self.id = config.stutendID
        #self.password = config.passward
        self.id = sys.argv[1]
        self.password = sys.argv[2]
        self.token = ""
        self.name = ""
        self.lt = ""
        self.my_session = requests.session()
        #self.sendMsg=sendMsg.sendMsg()

        self.login_url = 'https://e-report.neu.edu.cn/login'
        self.post_url = 'https://pass.neu.edu.cn/tpass/login'
        self.create_url = 'https://e-report.neu.edu.cn/notes/create'
        self.note_url = 'https://e-report.neu.edu.cn/api/notes'


    def login(self):
        #登陆,更新session
        msg=''
        try:
            login_response = self.my_session.get(self.login_url)
            self.lt = re.findall(r'LT-[0-9]*-[0-9a-zA-Z]*-tpass', login_response.text, re.S)[0]
            
            login_form_items = {
                'rsa': self.id + self.password + self.lt,
                'ul': str(len(self.id)),
                'pl': str(len(self.password)),
                'lt': self.lt,
                'execution': 'e1s1',
                '_eventId': 'submit'
            }
            post_response = self.my_session.post(self.post_url, login_form_items)
            msg=self.id+'登录成功!'
            #print("登陆成功!")
            #print("login success")
            print(1200)#返回的第一个数据,登陆成功
        except:
            msg=self.id+'登录失败!请手动完成打卡!'
            #print("登陆失败!")
            #print("login fail")
            print(1500)#返回的第一个数据,登陆失败
        return msg


    def healthDaka(self):
        #健康打卡
        msg=''
        success=False
        try:
            note_response = self.my_session.get(self.create_url)
            self.token = re.findall(r'name=\"_token\"\s+value=\"([0-9a-zA-Z]+)\"',note_response.text, re.S)[0]
            self.name = re.findall(r'当前用户:\s*(\w+)\s*', note_response.text, re.S)[0]

            health_items = {
                '_token': self.token,
                'jibenxinxi_shifoubenrenshangbao': '1',
                'profile[xuegonghao]': self.id,
                'profile[xingming]': self.name,
                'profile[suoshubanji]': '',
                'jiankangxinxi_muqianshentizhuangkuang': '正常',
                'xingchengxinxi_weizhishifouyoubianhua': '0',
                'cross_city': '无',
                'qitashixiang_qitaxuyaoshuomingdeshixiang': ''
            }
            health_response = self.my_session.post(self.note_url, health_items)
            if health_response.status_code == 201:
                #print(str(health_response) + '健康打卡成功')
                #msg=config.stutendID+'健康打卡成功!'
                #msg=config.stutendID+'健康打卡成功!'
                #print(str(health_response) + 'task success')
                print(2200)#返回的第二个数据,打卡成功
                #msg=config.stutendID+'健康打卡成功!'
                msg=self.id+'task success'
                success=True
            else:
                print(2500)#返回的第二个数据,打卡失败
                msg=self.id+'健康打卡失败!请手动完成打卡!'+ '(响应异常)'+str(health_response)
        except:
                msg=self.id+'健康打卡失败!请手动完成打卡!'+ '(执行异常)'
        return msg,success


    def temperatureDaka(self):
        #体温打卡
        msg=''
        success=False
        try:
            #hour = (time.localtime().tm_hour + 8) % 24   # 加8是因为腾讯云跑出来是格林时间,若是运行在自己服务器上需要改回来~
            hour = (time.localtime().tm_hour ) % 24  # 加8是因为腾讯云跑出来是格林时间,若是运行在自己服务器上需要改回来~
            temperature_url = 'https://e-report.neu.edu.cn/inspection/items/{}/records'.format(('1' if 7 <= hour <= 9 else '2' if 12 <= hour <= 14 else '3'))
            temperature_items = {
                '_token': self.token,
                'temperature': '36.5',
                'suspicious_respiratory_symptoms': '0',
                'symptom_descriptions': ''
            }
            temperature_response = self.my_session.post(temperature_url,    temperature_items)
            if temperature_response.status_code == 200:
                #print(str(temperature_response) + '体温打卡成功')
                #msg=config.stutendID+'体温打卡成功!'
                print(str(temperature_response) + 'temperature success')
                msg=self.id+'temperature success'
                success=True
            else:
                msg=self.id+'体温打卡失败!请手动完成打卡!'+ '(响应异常)'+str(temperature_response)
        except:
                msg=self.id+'体温打卡失败!请手动完成打卡!'+ '(执行异常)'
        return msg,success

def main_handler(event, context):
    _daka = daka()
    loginMsg = _daka.login()
    healthMsg, healSuc = _daka.healthDaka()
    #temperatureMsg, tempSuc = _daka.temperatureDaka()
    #早中晚体温打卡暂时就不做了

    #if config.sendMsgOnlyError and healSuc and tempSuc:
    #    pass
    #else:
    #    _daka.sendMsg.sendMessage(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime())+'\n'+loginMsg+'\n'+healthMsg+'\n'+temperatureMsg)

if __name__ == '__main__':
    main_handler(None,None)

依赖库:requests
执行方法:

python ./run.py 学号 密码

二、抓包分析

写脚本应该是一个逆向的过程这里我们也逆向进行解析
为了教学,特意改了密码

账号:20206041
密码:mima123456

通过以下界面登录
在这里插入图片描述
在这里插入图片描述
看这张图,我们可以看到登陆页面是向
https://portal.neu.edu.cn/desktop/api/sso/login
提交数据

rsa:学号+密码+未知字符串(姑且叫他流水号)
ul:id的长度
pl:密码的长度
it:流水号

除了流水号以外其他的数据我们都可以直接提交
从python脚本来看,流水号保存在登陆界面
就是https://portal.neu.edu.cn/desktop/api/sso/login这个页面的数据
我们去看一眼登陆界面的数据,果然找到了他

在这里插入图片描述
刚好一样(这个不好找,在浏览器的控制台也许能好找)
注意提交数据我看的是webforms
返回数据看的是raw

登陆问题解决

下面看提交页面都提交了哪些数据,从以下页面打卡
在这里插入图片描述

提交数据并抓包

在这里插入图片描述

				'_token': 未知字符串(这个不知道),
                'jibenxinxi_shifoubenrenshangbao': '1',
                'profile[xuegonghao]': 学号(这个执行脚本的时候就知道了),
                'profile[xingming]': 姓名(这个不知道),
                'profile[suoshubanji]': '',
                'jiankangxinxi_muqianshentizhuangkuang': '正常',
                'xingchengxinxi_weizhishifouyoubianhua': '0',
                'cross_city': '无',
                'qitashixiang_qitaxuyaoshuomingdeshixiang': ''

下面就是找到_token值和姓名
也是从上一界面查找(提交界面)

在这里插入图片描述
在这里插入图片描述
至此所有所需数据已经分析完毕,编写脚本

三、脚本编写

实现细则不做讨论(正则表达式提取部分),说一下大致逻辑
代码21行
requests.session()是为了保持cookie
跨请求保持某些参数,在同一个session实例发出的所有请求之间保持cookies

代码34、35行
来到登陆页面
从返回数据中提取下一步登录所需的流水号

代码63、64、65
来到健康上报页面,获取所需的_token和姓名

以上就是整个脚本的大致思路(不知道作者同不同意我这么说,只能说是作为新手的粗略理解)

他的url不全和我一样,我分析的url没有实践过,不过感觉应该也可以

;