要想完成本次 小功能程序需要 的环境:
- python 3.6 以上 (我用的是 3.6.7的) 此链接下载[提取码是: apge]
- QQ邮箱 授权码(大家自行百度)
相关依赖 (如果报错的话 没有那个库 就去 pip install 一下就好)
- requests_html (主要是这个 其它的【如果没记错的话】 都是python 自带的 不用去下载)
pip install requests_html -i https://pypi.douban.com/simple
需要注意的地方是 某某通里面的课程表需要自己 填补完成
废话不多说了 直接上代码吧
- 登陆模块
def moni_request():
'''
某某通 模拟登录 获取 cookie
:return: None
'''
email = '' # 账号
pwd = '' # 密码
url = 'http://passport2.chaoxing.com/login?newversion=true'
response = session.get(url)
fid = response.html.xpath('//input[@id="fid"]/@value')[0]
refer = response.html.xpath('//input[@id="refer"]/@value')[0]
forbidotherlogin = response.html.xpath('//input[@id="forbidotherlogin"]/@value')[0]
t = response.html.xpath('//input[@id="t"]/@value')[0]
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Host': 'passport2.chaoxing.com',
'Referer': 'http://passport2.chaoxing.com/login?newversion=true',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
pwd = str(base64.b64encode(pwd.encode('utf-8')), 'utf-8')
data = {
'fid': fid,
'uname': email,
'password': pwd,
'refer': refer,
't': t,
'forbidotherlogin': forbidotherlogin
}
url = 'http://passport2.chaoxing.com/fanyalogin'
session.post(url, data=data, headers=headers)
- 获取 课程表 信息
# 本周 课程表
def course_table():
'''
获取 本周的 课程表
:return: time_ 一天课程表 的安排
course 本周课程的 相关信息
'''
url = 'https://kb.chaoxing.com/pc/curriculum/getMyLessons'
data = session.get(url).json()['data']
time_ = data['curriculum']['lessonTimeConfigArray']
course = []
for i in data['lessonArray']:
dayOfWeek = i['dayOfWeek']
location = i['location']
beginNumber = i['beginNumber']
name = i['name'].split('-')[0] if '-' in i['name'] else i['name']
teacherName = i['teacherName']
course.append((name, teacherName, location, dayOfWeek, beginNumber))
return time_, course
- 获取当天的 课程 信息
# 获取 当天的 课程
def to_day_course(time_, course):
'''
处理 获取到的 课程时间安排 与课程
得到 当天的 课程与课程对应的时间
:param time_: 课程 时间安排
:param course: 本学期 的课程
:return: 处理后当天的 课程相关信息
'''
dayOfWeek = datetime.now().isoweekday()
data_time = []
for i in course:
if i[-2] == dayOfWeek:
data = (time_[i[-1] - 1].split('-')[0], i)
data_time.append(data)
return data_time
- 通过的到的相关课程信息,匹配出 当前时间 可能需要 模拟签到的 课程
def getLastedCourseInfo(currentCourse, course_name):
"""
:param currentCourse: 本学期的 课程详情
:param course_name: 当天最新的 可能可以 模拟签到的 科目
:return: 返回一个 url
"""
for i in currentCourse:
if i[1] == course_name:
return i[0]
return '没有找到相关课程'
- 这一点功能就是我 特别想实现的 功能(啊哈哈,大家都懂的…)------- 模拟签到
# 用于完成签到任务
def get_detail_course(url):
response = session.get(url)
courseid = response.html.xpath('//input[@id="courseid"]/@value')[0]
clazzid = response.html.xpath('//input[@id="clazzid"]/@value')[0]
fid = response.html.xpath('//input[@id="fid"]/@value')[0]
param = f'fid={fid}&courseId={courseid}&classId={clazzid}&_={int(time.time() * 1000)}'
url = 'https://mobilelearn.chaoxing.com/v2/apis/active/student/activelist'
response = session.get(url, params=param).json()['data']['activeList']
sign_id = []
TenXunUrl_list = []
for i in response:
if i['endTime'] // 1000 > time.time(): # 判断当前时间 是否 超过 通知有效时间
if i['type'] == 2: # 判断是不是 签到通知
sign_id.append(i['id'])
elif i['type'] == 64: # 判断 是不是会议id
url = json.loads(i['content'])['teaUrl'].decode()
TenXunUrl_list.append(url)
if not sign_id:
return '该课程还没有签到通知'
if TenXunUrl_list:
TenXunId = session.get('https://meeting.tencent.com/dm/YeclwuIgRbhx').html.xpath('//span[@id="tm-meeting-code"]/text()')[0]
send_message('会议地址地址', TenXunId)
# 自动签到
url = 'https://mobilelearn.chaoxing.com/v2/apis/sign/signIn'
data = f'activeId={sign_id[0]}'
response = session.get(url, params=data).json()
if response['msg'] == 'success':
logging.info(f'{response["data"]["name"]}\t签到 [成功] \n提交时间为{response["data"]["submittime"]}')
return response["data"]["submittime"]
else:
logging.warning(f'{response["data"]["name"]}\t签到 [异常] \n提交时间为{response["data"]["submittime"]}')
- 发送邮件
# 发送邮件
def send_message(suject, data):
'''
用于发送 qq邮箱
:param suject: 发送邮箱 的主题。一共有 三种 大类型 (当天课程提醒,签到成功,会议地址)
:param data: 用于 传递 相关发送 信息
:return: 返回 发送 成功与失败 (type=string)
'''
if suject == '当天课程提醒':
key_word = data
elif suject == '签到成功':
course_name, operator_time = data
key_word = f'<h1>{course_name}</h1><p>签到时间为:{operator_time}</p>'
else:
key_word = f'<p>这是会议的 会议id</p><p style="font-size:50px;color:green">{data}</p>'
msg_from = 'qqnumber@qq.com' # 发件人
msg_to = 'QQnumber@qq.com' # 收件人
msg = MIMEMultipart('related')
html_ = f"""
<html>
<body>
<div style="width: 100%; font-size: 20px;background-color: #5ebc5c;margin-top:-180px">{key_word}</div>
</body>
</html>
"""
content = MIMEText(html_, 'html', 'utf-8')
msg.attach(content)
msg['Subject'] = suject
msg['From'] = msg_from
msg['To'] = msg_to
passwd = '' # 生成的 授权码
try:
s = smtplib.SMTP_SSL("smtp.qq.com", 465)
s.login(msg_from, passwd)
s.sendmail(msg_from, msg_to, msg.as_string())
logging.info(f'邮件发送成功 [{suject}]')
return '发送成功'
except Exception as e:
logging.error(f'邮件发送失败 [{suject}][{e}]')
return '发送失败'
finally:
s.quit()
- 一个指定 线程的 函数 用于实现 发送 当天课程提醒信息 功能
# 指定的 线程函数
def func_Thead(Today_course):
'''
开启线程的 指定函数 也就是 完成 发送当天的 课程 安排 情况
:param Today_course: 当天 课程的 相关信息
:return: None
'''
data = f'<h2>今天一共{len(Today_course)}课</h2><br>'
count = 1
for i in Today_course:
data += f'<h2>第{count}节课:</h2><br>'
time_ = i[0]
course_name = i[1][0]
teacher_name = i[1][1]
address = i[1][2]
data += f'''
<p style="margin-left:30px;color:#619656">课程名称: {course_name}</p>
<p style="margin-left:30px;color:#619656">上课老师: {teacher_name}</p>
<p style="margin-left:30px;color:#619656">上课时间: {time_}</p>
<p style="margin-left:30px;color:#619656">上课地点: {address}</p>
'''
count += 1
while True:
if datetime.now().hour == 7 and datetime.now().minute >= 0:
if send_message('当天课程提醒', data) == '发送成功':
logging.info(f'当天课程提醒 发送 [成功] 信息:[{data}]')
break
time.sleep(120)
全部代码奉上
# -*- encoding: utf-8 -*-
# @Time : 9:24
# @Author : yuxian
# @File : demo.py
# @SoftWare : PyCharm
import base64
import json
import time
from requests_html import HTMLSession
from datetime import datetime
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
import smtplib
from threading import Thread
import logging
logging.basicConfig(level=logging.INFO, filename='utils.log',
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') # 指定日志 输出 格式
logger = logging.getLogger(__name__) # 创建 日志器
session = HTMLSession()
def moni_request():
'''
模拟登录 获取 cookie
:return: None
'''
email = ''
pwd = ''
url = 'http://passport2.chaoxing.com/login?newversion=true'
response = session.get(url)
fid = response.html.xpath('//input[@id="fid"]/@value')[0]
refer = response.html.xpath('//input[@id="refer"]/@value')[0]
forbidotherlogin = response.html.xpath('//input[@id="forbidotherlogin"]/@value')[0]
t = response.html.xpath('//input[@id="t"]/@value')[0]
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'Host': 'passport2.chaoxing.com',
'Referer': 'http://passport2.chaoxing.com/login?newversion=true',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36',
'X-Requested-With': 'XMLHttpRequest'
}
pwd = str(base64.b64encode(pwd.encode('utf-8')), 'utf-8')
data = {
'fid': fid,
'uname': email,
'password': pwd,
'refer': refer,
't': t,
'forbidotherlogin': forbidotherlogin
}
url = 'http://passport2.chaoxing.com/fanyalogin'
session.post(url, data=data, headers=headers)
# 本周 课程表
def course_table():
'''
获取 本周的 课程表
:return: time_ 一天课程表 的安排
course 本周课程的 相关信息
'''
url = 'https://kb.chaoxing.com/pc/curriculum/getMyLessons'
data = session.get(url).json()['data']
time_ = data['curriculum']['lessonTimeConfigArray']
course = []
for i in data['lessonArray']:
dayOfWeek = i['dayOfWeek']
location = i['location']
beginNumber = i['beginNumber']
name = i['name'].split('-')[0] if '-' in i['name'] else i['name']
teacherName = i['teacherName']
course.append((name, teacherName, location, dayOfWeek, beginNumber))
return time_, course
# 获取 今天的 课程
def to_day_course(time_, course):
'''
处理 获取到的 课程时间安排 与课程
得到 当天的 课程与课程对应的时间
:param time_: 课程 时间安排
:param course: 本学期 的课程
:return: 处理后当天的 课程相关信息
'''
dayOfWeek = datetime.now().isoweekday()
data_time = []
for i in course:
if i[-2] == dayOfWeek:
data = (time_[i[-1] - 1].split('-')[0], i)
data_time.append(data)
return data_time
# 当前时间 与 课程时间 比较
def get_nowTime(data):
'''
本函数 用于处理 当前时间 与 课程时间的 的关系
:param data: 当天 每一门课程的 相关信息
:return: type = bool型 如果满足设定的 条件 就返回 True 否则反之
'''
start = data
start_time = int(start.split(':')[0]) * 60 + int(start.split(':')[1])
now_time = datetime.now().hour * 60 + datetime.now().minute
if -30 <= start_time - now_time <= 3:
return True
return False
def getLastedCourseInfo(currentCourse, course_name):
"""
:param currentCourse: 本学期的 课程详情
:param course_name: 当天最新的 可能需要 模拟签到的 课程
:return: 返回一个 url
"""
for i in currentCourse:
if i[1] == course_name:
return i[0]
return '没有找到相关课程'
# 课程详细 路由 与名称
def course_data():
'''
获取 当前时间 最近的 一门课程 的请求地址 与 课程名称
:return:
'''
url = 'https://mooc1-2.chaoxing.com/visit/courselistdata'
headers = {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
'X-Requested-With': 'XMLHttpRequest'
}
data = 'courseType=1&courseFolderId=0&courseFolderSize=0'
response = session.post(url, headers=headers, data=data)
url_name = response.html.xpath('//h3[@class="inlineBlock"]/a/@href | //h3[@class="inlineBlock"]/a/span/@title')
return [(url_name[i], url_name[i + 1]) for i in range(0, len(url_name), 2)]
# 完成签到任务
def get_detail_course(url):
response = session.get(url)
courseid = response.html.xpath('//input[@id="courseid"]/@value')[0]
clazzid = response.html.xpath('//input[@id="clazzid"]/@value')[0]
fid = response.html.xpath('//input[@id="fid"]/@value')[0]
param = f'fid={fid}&courseId={courseid}&classId={clazzid}&_={int(time.time() * 1000)}'
url = 'https://mobilelearn.chaoxing.com/v2/apis/active/student/activelist'
response = session.get(url, params=param).json()['data']['activeList']
sign_id = []
TenXunUrl_list = []
for i in response:
if i['endTime'] // 1000 > time.time(): # 判断当前时间 是否 超过 通知有效时间
if i['type'] == 2: # 判断是不是 签到通知
sign_id.append(i['id'])
elif i['type'] == 64: # 判断 是不是会议
url = json.loads(i['content'])['teaUrl'].decode()
TenXunUrl_list.append(url)
if not sign_id:
return '该课程还没有签到通知'
if TenXunUrl_list:
TenXunId = session.get('https://meeting.tencent.com/dm/YeclwuIgRbhx').html.xpath('//span[@id="tm-meeting-code"]/text()')[0]
send_message('会议地址', TenXunId)
# 自动签到
url = 'https://mobilelearn.chaoxing.com/v2/apis/sign/signIn'
data = f'activeId={sign_id[0]}'
response = session.get(url, params=data).json()
if response['msg'] == 'success':
logging.info(f'{response["data"]["name"]}\t签到 [成功] \n提交时间为{response["data"]["submittime"]}')
return response["data"]["submittime"]
else:
logging.warning(f'{response["data"]["name"]}\t签到 [异常] \n提交时间为{response["data"]["submittime"]}')
# 发送邮件
def send_message(suject, data):
'''
用于发送 qq邮箱
:param suject: 发送邮箱 的主题。一共有 三种 大类型 (当天课程提醒,签到成功,会议地址)
:param data: 用于 传递 相关发送 信息
:return: 返回 发送 成功与失败 (type=string)
'''
if suject == '当天课程提醒':
key_word = data
elif suject == '签到成功':
course_name, operator_time = data
key_word = f'<h1>{course_name}</h1><p>签到时间为:{operator_time}</p>'
else:
key_word = f'<p>这是会议的 会议id</p><p style="font-size:50px;color:green">{data}</p>'
msg_from = ''
msg_to = ''
msg = MIMEMultipart('related')
html_ = f"""
<html>
<body>
<div style="width: 100%; font-size: 20px;background-color: #5ebc5c;margin-top:-180px">{key_word}</div>
</body>
</html>
"""
content = MIMEText(html_, 'html', 'utf-8')
msg.attach(content)
msg['Subject'] = suject
msg['From'] = msg_from
msg['To'] = msg_to
passwd = ''
try:
s = smtplib.SMTP_SSL("smtp.qq.com", 465)
s.login(msg_from, passwd)
s.sendmail(msg_from, msg_to, msg.as_string())
logging.info(f'邮件发送成功 [{suject}]')
return '发送成功'
except Exception as e:
logging.error(f'邮件发送失败 [{suject}][{e}]')
return '发送失败'
finally:
s.quit()
# 指定的 线程函数
def func_Thead(Today_course):
'''
开启线程的 指定函数 也就是 完成 发送当天的 课程 安排 情况
:param Today_course: 当天 课程的 相关信息
:return: None
'''
data = f'<h2>今天一共{len(Today_course)}课</h2><br>'
count = 1
for i in Today_course:
data += f'<h2>第{count}节课:</h2><br>'
time_ = i[0]
course_name = i[1][0]
teacher_name = i[1][1]
address = i[1][2]
data += f'''
<p style="margin-left:30px;color:#619656">课程名称: {course_name}</p>
<p style="margin-left:30px;color:#619656">上课老师: {teacher_name}</p>
<p style="margin-left:30px;color:#619656">上课时间: {time_}</p>
<p style="margin-left:30px;color:#619656">上课地点: {address}</p>
'''
count += 1
while True:
if datetime.now().hour == 7 and datetime.now().minute >= 0:
if send_message('当天课程提醒', data) == '发送成功':
logging.info(f'当天课程提醒 发送 [成功] 信息:[{data}]')
break
time.sleep(120)
if __name__ == '__main__':
attention = [] # 用于校验 是否 今天的课程 是否 已经 自动签到
moni_request()
time_, courses = course_table()
Today_course = to_day_course(time_, courses)
Thread(target=func_Thead, args=(Today_course,)).start() # 启用线程
currentCourse = course_data()
while True:
for course in Today_course:
if get_nowTime(course[0]): # 判断 最新时间 是否 满足条件
url_or_other = getLastedCourseInfo(course[1][0], currentCourse)
if url_or_other != '没有找到相关课程':
sign_return = get_detail_course(url_or_other)
if sign_return != '该课程还没有签到通知':
send_message('签到成功', (course[1][0], sign_return))
attention.append(course[1][0])
else:
continue
time.sleep(20)
if len(Today_course) == len(attention):
break
time.sleep(60)
第一次 写博客(写这篇文章纯属娱乐,大佬勿喷,哈哈) 有错误的地方请大佬指正,看都看到这里 点个赞呗。最后,这篇文章纯属 用于个人 娱乐,无侵犯之意(如有侵权之处,请告知)