forked from GhostFrankWu/SUSTech_Tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
main.py
216 lines (199 loc) · 9.76 KB
/
main.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/usr/bin/env python3 # -*- coding: utf-8 -*
"""
main.py 南科大TIS喵课助手
@CreateDate 2021-1-9
@UpdateDate 2023-2-9
modified by jrx: 修正了Max retries exceeded with url的错误
"""
import _thread
import time
import requests
from os import path
from re import findall
from json import loads
from colorama import init
# from requests.packages.urllib3.exceptions import InsecureRequestWarning
# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
head = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.0.0 Safari/537.36",
"x-requested-with": "XMLHttpRequest"
}
def cas_login(user_name, pwd):
""" 用于和南科大CAS认证交互,拿到tis的有效cookie
输入用于CAS登录的用户名密码,输出tis需要的全部cookie内容(返回头Set-Cookie段的route和jsessionid)
我的requests的session不吃CAS重定向给到的cookie,不知道是代码哪里的问题,所以就手动拿了 """
print("[\x1b[0;36m!\x1b[0m] " + "测试CAS链接...")
try: # Login 服务的CAS链接有时候会变
login_url = "https://cas.sustech.edu.cn/cas/login?service=https%3A%2F%2Ftis.sustech.edu.cn%2Fcas"
req = requests.get(login_url, headers=head)
assert (req.status_code == 200)
print("[\x1b[0;32m+\x1b[0m] " + "成功连接到CAS...")
except:
print("[\x1b[0;31mx\x1b[0m] " + "不能访问CAS, 请检查您的网络连接状态")
return "", ""
print("[\x1b[0;36m!\x1b[0m] " + "登录中...")
data = { # execution大概是CAS中前端session id之类的东西
'username': user_name,
'password': pwd,
'execution': str(req.text).split('''name="execution" value="''')[1].split('"')[0],
'_eventId': 'submit',
}
req = requests.post(login_url, data=data, allow_redirects=False, headers=head)
if "Location" in req.headers.keys():
print("[\x1b[0;32m+\x1b[0m] " + "登录成功")
else:
print("[\x1b[0;31mx\x1b[0m] " + "用户名或密码错误,请检查")
return "", ""
req = requests.get(req.headers["Location"], allow_redirects=False, headers=head, verify=False)
route_ = findall('route=(.+?);', req.headers["Set-Cookie"])[0]
jsessionid = findall('JSESSIONID=(.+?);', req.headers["Set-Cookie"])[0]
return route_, jsessionid
def getinfo(semester_data):
""" 用于向tis请求当前学期的课程ID,得到的ID将用于选课的请求
输入当前学期的日期信息,返回的json包括了课程名和内部的ID """
course_list = []
course_types = {'bxxk': "通识必修选课", 'xxxk': "通识选修选课", "kzyxk": '培养方案内课程', "zynknjxk": '非培养方案内课程', "jhnxk": '计划内选课新生'}
# f = open("test"+".txt", "w+")
# raw_data_file = open("rawdata.txt", "w+")
for course_type in course_types.keys():
# print(str(course_type) + "\n")
data = {
"p_xn": semester_data['p_xn'], # 当前学年
"p_xq": semester_data['p_xq'], # 当前学期
"p_xnxq": semester_data['p_xnxq'], # 当前学年学期
"p_pylx": 1,
"mxpylx": 1,
"p_xkfsdm": course_type,
"pageNum": 1,
"pageSize": 1000 # 每学期总共开课在1000左右,所以单组件可以包括学期的全部课程
}
req = requests.post('https://tis.sustech.edu.cn/Xsxk/queryKxrw', data=data, headers=head, verify=False)
raw_class_data = loads(req.text)
for rawkey, rawvalue in raw_class_data.items():
if rawkey == 'kxrwList':
continue
# raw_data_file.write(str(rawkey) + "\n")
# raw_data_file.write(str(rawvalue) + "\n" + "\n")
classData = {}
if 'kxrwList' in raw_class_data.keys():
if raw_class_data['kxrwList'] is None:
continue
for i in raw_class_data['kxrwList']['list']:
if i is not None:
# f.write("hhhhh " + str(i) + "\n")
classData[i['rwmc']] = i['id']
# 分析要喵课程的ID
for name in classList:
name = name.strip()
if name in classData.keys():
course_list.append([classData[name], course_type, name])
# raw_data_file.close()
# f.close()
print("[\x1b[0;32m+\x1b[0m] " + "课程信息读取完毕")
print("[\x1b[0;34m{}\x1b[0m]".format("=" * 25))
for course in course_list:
print(course_types[course[1]] + " : " + course[2], end="")
print(" ID 为: " + course[0])
print("[\x1b[0;34m{}\x1b[0m]".format("=" * 25))
print("[\x1b[0;32m+\x1b[0m] " + "成功读入以上信息")
print()
return course_list
def submit(semester_data, course):
""" 用于向tis发送喵课的请求
本段函数会在多线程中调用,因为我不知道python神奇的GIL到底会在什么时候干预,所以尽量不用全局变量会共享的变量
(什么,购物车是怎么回事?那首先排除教务系统是个魔改的电商项目)"""
data = {
"p_pylx": 1,
"p_xktjz": "rwtjzyx", # 提交至,可选任务,rwtjzgwc提交至购物车,rwtjzyx提交至已选 gwctjzyx购物车提交至已选
"p_xn": semester_data['p_xn'],
"p_xq": semester_data['p_xq'],
"p_xnxq": semester_data['p_xnxq'],
"p_xkfsdm": course[1], # 选课方式
"p_id": course[0], # 课程id
"p_sfxsgwckb": 1, # 固定
}
req = requests.post('https://tis.sustech.edu.cn/Xsxk/addGouwuche', data=data, headers=head, verify=False)
if "成功" in req.text:
print("[\x1b[0;34m{}\x1b[0m]".format("=" * 50), flush=True)
print("[\x1b[0;34m█\x1b[0m]\t\t\t" + loads(req.text)['message'], flush=True)
print("[\x1b[0;34m{}\x1b[0m]".format("=" * 50), flush=True)
else:
print("[\x1b[0;30m-\x1b[0m]\t\t\t" + loads(req.text)['message'], flush=True)
def load_course():
""" 用于加载本地要喵的课程
如果存在文件就读文件里的,不存在就手动录入
有些(我忘了是哪些了)情况会在文件头会有几个不可见字符,但是会被python读进来,所以第一行建议忽略留空"""
cache_path = "Class.txt"
classes = []
if path.exists(cache_path) and path.isfile(cache_path):
print("[\x1b[0;36m!\x1b[0m] " + "读取规划课表...")
with open(cache_path, "r", encoding="utf8") as f:
classes = f.readlines()
print("[\x1b[0;32m+\x1b[0m] " + "规划课表读取完毕")
else:
print("[\x1b[0;33m-\x1b[0m] " + "没有找到规划课表,请手动输入课程信息,输入-1结束录入")
while True:
s = input()
if s == "-1":
break
else:
classes.append(s)
s = input("[\x1b[0;36m!\x1b[0m] " + "是否保存录入的信息(y/N)?")
if s == "Y" or s == "y":
with open(cache_path, "w", encoding="utf8") as f:
f.write("===本文件是待喵课程的列表,一行输入一个课程名字==请勿删除本行===\n")
for course in classes:
f.write(course + "\n")
f.close()
return classes
if __name__ == '__main__':
init(autoreset=True) # 某窗口系统的优质终端并不直接支持如下转义彩色字符,所以需要一些库来帮忙
classList = load_course() # 读取本地待喵的课程
# 下面是CAS登录
route, JSESSIONID = "", ""
while route == "" or JSESSIONID == "":
userName = input("请输入您的学号:") # getpass在PyCharm里不能正常工作,请改为input或写死
passWord = input("请输入CAS密码(输入的密码将直接显示):")
route, JSESSIONID = cas_login(userName, passWord)
if route == "" or JSESSIONID == "":
print("[\x1b[0;33m-\x1b[0m] " + "请重试...")
head['cookie'] = f'route={route}; JSESSIONID={JSESSIONID};'
# 下面先获取当前的学期
print("[\x1b[0;36m!\x1b[0m] " + "从服务器获取当前喵课时间...")
semester_info = loads( # 这里要加mxpylx才能获取到选课所在最新学期
requests.post('https://tis.sustech.edu.cn/Xsxk/queryXkdqXnxq', data={"mxpylx": 1}, headers=head, verify=False).text)
print("[\x1b[0;32m+\x1b[0m] " + f"当前学期是{semester_info['p_xn']}学年第{semester_info['p_xq']}学期,为"
f"{['', '秋季', '春季', '小'][int(semester_info['p_xq'])]}学期")
# 下面获取课程信息
print("[\x1b[0;36m!\x1b[0m] " + "从服务器下载课程信息,请稍等...")
postList = getinfo(semester_info)
print("[\x1b[0;32m+\x1b[0m] " + "开始喵课")
# 喵课主逻辑
while True:
print("[\x1b[0;32m+\x1b[0m] " + "按一下回车对列表内所有课程喵一次,多按同时喵多次")
# input()
for c_id in postList:
try:
for _ in range(1):
_thread.start_new_thread(submit, (semester_info, c_id))
time.sleep(1)
except:
print("线程异常")
"""
# timing is everything!
import datetime,time
start = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '12:55', '%Y-%m-%d%H:%M')
end = datetime.datetime.strptime(str(datetime.datetime.now().date()) + '13:05', '%Y-%m-%d%H:%M')
while True:
n_time = datetime.datetime.now()
if start < n_time < end:
for c_id in postList:
try:
submit(semester_info, c_id)
except:
pass
time.sleep(0xdeadbeef)
time.sleep(0xc0febabe)
"""