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

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

关键词

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

0-引言

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

1-总流程图

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

2.1-抓包解析过程

部分关键信息已经打码
打开fiddler和我在校园小程序,登录,抓取到登录信息如下
基于阿里云服务器的我在校园班委自动管理系统
基于阿里云服务器的我在校园班委自动管理系统
由其中发现,我在校园登录是通过url中的符号 ? 来实现传值的,由于登录的时候没有后面的openid等值,猜测传入账号和密码就可以实现登录。
经检验,猜测正确。
按照正常流程进入班级管理界面,依次进入日渐日报管理和班级签到管理,而后检查抓包信息
我在校园班级管理界面
基于阿里云服务器的我在校园班委自动管理系统
日检日报界面
基于阿里云服务器的我在校园班委自动管理系统
同理进入签到页面检查,发现出入的参数有一个id
基于阿里云服务器的我在校园班委自动管理系统
经检查,在上一级页面的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-配置文件

文件如图配置
基于阿里云服务器的我在校园班委自动管理系统
基于阿里云服务器的我在校园班委自动管理系统

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

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

3-过程碰到的问题

3.1-抓取不到登录界面

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

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

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

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

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

上一篇:阿里、华为、腾讯 云服务器端口配置教程汇总


下一篇:【合集】云栖大会珍贵技术资料:20+覆盖容器技术、智能工业、大数据、开源数据库等(上)