基于阿里云服务器的我在校园班委自动管理系统

简介: 利用python构造程序放置于阿里云服务器,实现我在校园固定时间点,自动通过邮箱提醒未完成日检日报、签到的同学完成打卡,以及程序的实现过程。

本文仅用于学习用途,转载请注明出处

关键词

python、fiddler抓包、服务器、我在校园、HTTP

0-引言

因学校要求,班委需提醒未完成打卡同学打卡,否则扣除德育分,影响德育成绩。所以为实现班委我在校园的自动化管理,尝试使用python编写一个爬虫程序挂靠在服务器运行,实现每天的自动提醒管理。
经前期搜索,互联网上的我在校园爬虫未涉及班委的自动化管理,且仅仅通过token或者JWSESSION实现登录,时效性不好且操作麻烦。例如github上面的我在校园自动签到程序,通过token值实现签到,但现已经停止维护,且token值登录已经被我在校园登录给禁止。csdn和博客园的部分文章仅仅涉及通过抓包获取JWSESSION实现登录签到,但是有效期不长。

1-总流程图

总流程图.jpg

2.1-抓包解析过程

部分关键信息已经打码
打开fiddler和我在校园小程序,登录,抓取到登录信息如下
登录表头1.png
登录表头2.png
由其中发现,我在校园登录是通过url中的符号 ? 来实现传值的,由于登录的时候没有后面的openid等值,猜测传入账号和密码就可以实现登录。
经检验,猜测正确。
按照正常流程进入班级管理界面,依次进入日渐日报管理和班级签到管理,而后检查抓包信息
我在校园班级管理界面
我在校园班级管理界面.jpg
日检日报界面
日检日报.png
同理进入签到页面检查,发现出入的参数有一个id
签到图1.png
经检查,在上一级页面的respond的中,发现了该天的id,图略

2.2-构建爬虫程序

代码有注释,变量均采用英文命名,可直接阅读

#!/usr/bin/env Python
# coding=utf-8
import requests
import json
import time


class auto_tips:
    def __init__(self, username, password):
        self.not_heat_names_list = []
        self.not_sign_names_list = []
        # 保留登录信息
        self.session = requests.session()
        self.cookies = None

        # 登入界面的post信息
        self.login_url = 'https://gw.wozaixiaoyuan.com/basicinfo/mobile/login/username'
        self.login_data = {
            'username': username,
            'password': password
        }
        self.login_headers = {
            'Host': 'gw.wozaixiaoyuan.com',
            'Connection': 'keep-alive',
            'Content-Length': '2',
            'Accept': 'application/json, text/plain, */*',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
            'Content-Type': 'application/json;charset=UTF-8',
            'Sec-Fetch-Site': 'same-origin',
            'Sec-Fetch-Mode': 'cors',
            'Sec-Fetch-Dest': 'empty',
            'Accept-Encoding': 'gzip, deflate, br',
            'Accept-Language': 'en-us,en'
        }
        # 班级日检日报的信息
        self.getHeatUsers_url = 'https://student.wozaixiaoyuan.com/heat/getHeatUsers.json'
        self.getHeatUsers_headers = {
            'Host': 'student.wozaixiaoyuan.com',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
            'content-type': 'application/x-www-form-urlencoded',
            'Accept-Encoding': 'gzip, deflate, br'
        }
        self.getHeatUsers_data = {'seq': '1', 'date': str(time.strftime("%Y%m%d")), 'type': '0'}  # 测试用的,后边程序会更改
        # 校区签到的列表
        self.getList_url = 'https://student.wozaixiaoyuan.com/gradeManage/sign/getList.json'
        self.getList_headers = {
            'Host': 'student.wozaixiaoyuan.com',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
            'content-type': 'application/x-www-form-urlencoded',
            'Accept-Encoding': 'gzip, deflate, br'
        }
        self.getList_date = {
            'keyword': '',
            'page': '1'
        }
        # 校区签到的班级成员情况
        self.getSignResult_url = 'https://student.wozaixiaoyuan.com/gradeManage/sign/getSignResult.json'
        self.getSignResult_headers = {
            'Host': 'student.wozaixiaoyuan.com',
            'Connection': 'keep-alive',
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36 MicroMessenger/7.0.9.501 NetType/WIFI MiniProgramEnv/Windows WindowsWechat',
            'content-type': 'application/x-www-form-urlencoded',
            'Accept-Encoding': 'gzip, deflate, br'
        }
        self.getSignResult_data = {
            'id': ''
        }

    def login(self):  # 登入账号
        self.login_url = self.login_url + "?username=" + str(self.login_data['username']) + "&password=" + str(
            self.login_data['password'])  # 通过 url 的 '?' 方法写入参数  # 更新url
        res = self.session.post(url=self.login_url, headers=self.login_headers, data='{}')
        try:
            if json.loads(res.text)['code'] == 0:
                self.session.cookies.set('JWSESSION', res.headers['JWSESSION'])  # 更新JWSESSION值
                print('{}\t登录成功'.format(time.strftime("%H:%M:%S")))
            else:
                print('{}\t登录失败:{}'.format(time.strftime("%H:%M:%S"), json.loads(res.text)['message']))  # 输出登录错误的错误原因
        except:
            print('{}\t登录错误'.format(time.strftime("%H:%M:%S")))

    def get_HeatUsers(self):
        try:
            res = self.session.post(url=self.getHeatUsers_url, headers=self.getHeatUsers_headers,
                                    data=self.getHeatUsers_data)
            if json.loads(res.text)['code'] == 0:  # 检查是否请求成功且正确
                # print('{}\t成功获得班级成员日检日报信息'.format(time.strftime("%H:%M:%S")))
                data = json.loads(res.text)['data']   # 观察是否有不晨检的同学
                if len(data) != 0:
                    for inf in data:  # 如果有,则更新不晨检列表
                        name = inf['name']
                        self.not_heat_names_list.append(name)
                    print('{}\t未完成日检日报的班级成员为{}'.format(time.strftime("%H:%M:%S"), self.not_heat_names_list))
                else:
                    print('{}\t班级成员全部完成日检日报'.format(time.strftime("%H:%M:%S")))

            else:
                print('{}\t获得班级成员日检日报信息失败:{}'.format(time.strftime("%H:%M:%S"), json.loads(res.text)['message']))  # 输出登录错误的错误原因
        except:
            print('{}\t获得班级成员日检日报信息失败'.format(time.strftime("%H:%M:%S")))

    def get_SignResult(self):
        # 获取当天的签到 id 值
        try:
            res = self.session.post(url=self.getList_url, headers=self.getList_headers,
                                    data=self.getList_date)
            if json.loads(res.text)['data'][0]['end'].split(' ')[0] == time.strftime("%Y-%m-%d"):  # 判断第一个签到是不是当天的签到
                self.getSignResult_data['id'] = json.loads(res.text)['data'][0]['id']  # 如果判断成功,则更新 查询签到的id
                res = self.session.post(url=self.getSignResult_url, headers=self.getSignResult_headers,  # 查询签到
                                        data=self.getSignResult_data)
                data = json.loads(res.text)['data']
                if len(data['notSign']) != 0:  # 判断是否有成员不签到
                    for inf in data['notSign']:
                        name = inf['name']
                        self.not_sign_names_list.append(name)
                    print('{}\t未完成签到的班级成员为{}'.format(time.strftime("%H:%M:%S"), self.not_sign_names_list))
                else:
                    print('{}\t班级成员全部完成签到'.format(time.strftime("%H:%M:%S")))
        except:
            print('{}\t获得班级成员签到信息失败'.format(time.strftime("%H:%M:%S")))


if __name__ == '__main__':
    obj = auto_tips('账号名', '密码')
    obj.login()
    obj.get_HeatUsers()
    obj.get_SignResult()

2.3-构建邮件提醒程序

同上,可直接阅读

import smtplib
from email.mime.text import MIMEText
# email 用于构建邮件内容
from email.header import Header


class email_obj:
    def __init__(self, to_addr=None, email_Subject=None, email_content=None):
        data_inf_path = r'系统日志\email_data.txt'   # 邮箱信息的存储路径
        with open(data_inf_path, 'r+', encoding='UTF-8') as f:
            data_inf = eval(f.read())  # 读取邮箱信息
            f.close()
        self.from_addr = data_inf['发信邮箱']  # 发信邮箱
        self.password = data_inf['邮箱授权码']  # 发信邮箱的授权码
        self.smtp_server = data_inf['发信服务器']  # 发信服务器的域名
        self.to_addr = to_addr  # 收信邮箱
        self.email_Subject = email_Subject  # 邮件标题
        self.email_content = email_content  # 邮件内容

        # 开启发信服务,这里使用的是加密传输
        self.server = smtplib.SMTP_SSL(host=self.smtp_server)  # POP3/SMTP 协议的发送邮件服务器
        self.server.connect(self.smtp_server, 465)  # 使用SSL,端口号465
        # 登录发信邮箱
        self.server.login(self.from_addr, self.password)

    def change_email_inf_to(self, to_addr, email_Subject, email_content):
        self.to_addr = to_addr  # 收信邮箱
        self.email_Subject = email_Subject  # 邮件标题
        self.email_content = email_content  # 邮件内容

    def send(self):
        # 邮箱正文内容,第一个参数为内容,第二个参数为格式(plain 为纯文本),第三个参数为编码
        msg = MIMEText(self.email_content, 'plain', 'utf-8')

        # 邮件头信息
        msg['From'] = Header(self.from_addr)
        msg['To'] = Header(self.to_addr)
        msg['Subject'] = Header(self.email_Subject)

        # 发送邮件
        self.server.sendmail(self.from_addr, self.to_addr, msg.as_string())

    def close(self):
        # 关闭服务器
        self.server.quit()


if __name__ == '__main__':
    to_addr = 'xxx@xx.xxx'
    email_Subject = 'send by python'
    email_content = 'python test'
    obj = email_obj(to_addr, email_Subject, email_content)
    obj.send()

定时触发程序

#!/usr/bin/env Python
# coding=utf-8
import tips
import send_email
import pandas as pd
import time


def heat_tip(file):  # 晨检提醒
    obj = tips.auto_tips('真实账号', '真实密码')
    obj.login()
    obj.get_HeatUsers()
    name_list = obj.not_heat_names_list
    if len(name_list) != 0:
        user_email = send_email.email_obj()  # 登录邮箱
        for i in range(len(name_list)):  # 依次编辑文件
            name_i = name_list[i]
            for j in range(len(file)):
                name_j = file.iloc[j, 0]
                if name_i == name_j:
                    qq = file.iloc[j, 1]
                    qq_email = qq + '@qq.com'
                    email_Subject = '日检日报提醒'
                    email_content = '赶紧晨检了,现在已经是{}了'.format(time.strftime("%H:%M:%S"))
                    user_email.change_email_inf_to(to_addr=qq_email, email_Subject=email_Subject,
                                                      email_content=email_content)
                    user_email.send()
        user_email.close()  # 退出邮箱


def sign_tip(file):  # 签到提醒
    obj = tips.auto_tips('真实账号', '真实密码')
    obj.login()
    obj.get_SignResult()
    name_list = obj.not_sign_names_list
    if len(name_list) != 0:
        user_email = send_email.email_obj()  # 登录邮箱
        for i in range(len(name_list)):  # 依次编辑文件
            name_i = name_list[i]
            for j in range(len(file)):
                name_j = file.iloc[j, 0]
                if name_i == name_j:
                    qq = file.iloc[j, 1]
                    qq_email = qq + '@qq.com'
                    email_Subject = '签到提醒'
                    email_content = '赶紧晨检了,现在已经是{}了'.format(time.strftime("%H:%M:%S"))
                    user_email.change_email_inf_to(to_addr=qq_email, email_Subject=email_Subject,
                                                   email_content=email_content)
                    user_email.send()
        user_email.close()  # 退出邮箱


def seconds(now_time):  # 把时间转化为秒
    hour = int(now_time.split(':')[0])
    minute = int(now_time.split(':')[1])
    second = int(now_time.split(':')[2])
    now_seconds = hour * 60 * 60 + minute * 60 + second
    return now_seconds


def get_sleep_time(now_time, to_time):  # 获得程序睡眠时间
    sleep_time = seconds(to_time) - seconds(now_time)
    return sleep_time  # 单位是s


def auto_tips():
    file = pd.read_excel(r'用户信息\班级成员信息.xlsx')
    print('开始运行')
    # 晨检提醒时间
    heat_tip_time_1 = '11:00:00'
    heat_tip_time_2 = '11:30:00'
    heat_tip_time_3 = '11:50:00'
    # 签到提醒时间
    sign_tip_time_1 = '22:05:00'
    sign_tip_time_2 = '22:15:00'
    sign_tip_time_3 = '22:25:00'
    tips_time_list = [heat_tip_time_1, heat_tip_time_2, heat_tip_time_3, sign_tip_time_1, sign_tip_time_2,
                      sign_tip_time_3]  # 按顺序放好
    ####
    while True:
        flag = 0  # 判断当前时间是否在提醒时间前
        tip_name = None  # 提醒的事件名称
        sleep_time = None  # 睡眠时间
        for i in range(len(tips_time_list)):  # 判断当前时间
            tip_time = tips_time_list[i]
            now_time = time.strftime("%H:%M:%S")  # 时:分:秒
            if seconds(now_time) < seconds(tip_time): 
                sleep_time = get_sleep_time(now_time=now_time, to_time=tip_time)
                if i <= 2:
                    tip_name = '晨检'
                else:
                    tip_name = '签到'
                flag = 1
                break
        if flag == 0:
            now_time = time.strftime("%H:%M:%S")  # 时:分:秒
            sleep_time = get_sleep_time(now_time=now_time, to_time='24:00:00') + get_sleep_time(now_time='00:00:00',
                                                                                                to_time=tips_time_list[0])
            tip_name = '晨检'
        print('{}\t即将休眠{}秒'.format(time.strftime("%H:%M:%S"), sleep_time))
        time.sleep(sleep_time)
        if tip_name == '晨检':
            heat_tip(file)
        elif tip_name == '签到':
            sign_tip(file)
        print('{}\t提醒信息已经发送'.format(time.strftime("%H:%M:%S")))


if __name__ == '__main__':
    # print(seconds('07:10:12'))
    auto_tips()

2.4-配置文件

文件如图配置
程序配置.png
文件信息.jpg

2.5-打包并且配置到服务器上

利用pyinstaller打包auto_tips.py
然后用命令控制符的mstsc命令,连接远程服务器,把整个文件夹上传到服务器运行。

3-过程碰到的问题

3.1-抓取不到登录界面

问题描述打开微信小程序,进入我在校园后,只获得了get信息,然后就自动转接微信授权登录,无法抓取到post信息
解决方法换另一台电脑登录后,再重新返回本电脑登录我在校园,微信授权登录就会失败,然后就可以账号密码登入,抓取到对应的信息

3.2-获取不了邮箱的授权码

问题描述我用的是阿里云购买的域名,解析到腾讯企业邮箱的服务器上,注册了域名邮箱。找不到对应的授权码
解决方法打开腾讯企业邮箱,给对应的邮箱开头SMTP服务,然后进入邮箱,设置中处理就可以了。详细教程网上可以查到

3.3nssm-把exe文件注册成服务

问题描述把exe文件通过nssm程序注册成计算机服务,后台运行服务时候,运行失败
暂未解决

相关实践学习
2分钟自动化部署人生模拟器
本场景将带你借助云效流水线Flow实现人生模拟器小游戏的自动化部署
7天玩转云服务器
云服务器ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,可降低 IT 成本,提升运维效率。本课程手把手带你了解ECS、掌握基本操作、动手实操快照管理、镜像管理等。了解产品详情:&nbsp;https://www.aliyun.com/product/ecs
相关文章
|
26天前
|
监控 Java Linux
Linux系统之安装Ward服务器监控工具
【10月更文挑战第17天】Linux系统之安装Ward服务器监控工具
49 5
Linux系统之安装Ward服务器监控工具
|
1月前
|
存储 监控 网络协议
服务器压力测试是一种评估系统在极端条件下的表现和稳定性的技术
【10月更文挑战第11天】服务器压力测试是一种评估系统在极端条件下的表现和稳定性的技术
108 32
|
21天前
|
存储 安全 关系型数据库
Linux系统在服务器领域的应用与优势###
本文深入探讨了Linux操作系统在服务器领域的广泛应用及其显著优势。通过分析其开源性、安全性、稳定性和高效性,揭示了为何Linux成为众多企业和开发者的首选服务器操作系统。文章还列举了Linux在服务器管理、性能优化和社区支持等方面的具体优势,为读者提供了全面而深入的理解。 ###
|
24天前
|
NoSQL Linux PHP
|
1月前
|
Apache 数据中心 Windows
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
将网站迁移到阿里云Windows系统云服务器,访问该站点提示连接被拒绝,如何处理?
|
1月前
|
域名解析 缓存 网络协议
Windows系统云服务器自定义域名解析导致网站无法访问怎么解决?
Windows系统云服务器自定义域名解析导致网站无法访问怎么解决?
|
2月前
|
监控 安全 Unix
服务器系统
服务器系统
41 7
|
1月前
|
存储 监控 Linux
充分利用服务器的磁盘资源,提高系统的稳定性和可维护性
充分利用服务器的磁盘资源,提高系统的稳定性和可维护性
36 0
|
2月前
|
存储 弹性计算 运维
自动化监控和响应ECS系统事件
阿里云提供的ECS系统事件用于记录云资源信息,如实例启停、到期通知等。为实现自动化运维,如故障处理与动态调度,可使用云助手插件`ecs-tool-event`。该插件定时获取并转化ECS事件为日志存储,便于监控与响应,无需额外开发,适用于大规模集群管理。详情及示例可见链接文档。
|
1月前
|
弹性计算 安全 关系型数据库
阿里云国际版远程连接Windows系统的ECS服务器时提示协议错误
阿里云国际版远程连接Windows系统的ECS服务器时提示协议错误