-
Notifications
You must be signed in to change notification settings - Fork 0
/
YdszTool.py
331 lines (309 loc) · 15.2 KB
/
YdszTool.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
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
import ssl
import urllib.parse
import urllib.request
from json import loads
from time import sleep
from re import search, S
from random import choice
from http import cookiejar
from base64 import b64encode
from datetime import datetime
from requests import get, post
from Cryptodome.Cipher import AES
from urllib3 import disable_warnings
from tkinter import Tk, StringVar, Label, Entry, Button, ttk
class Ydsz:
def __init__(self, iusername, ipassword, iday, istarttime, iendtime, imax_site, ishopnum, ipost_type):
# Disable SSL warnings
disable_warnings()
ssl._create_default_https_context = ssl._create_unverified_context
# 参数
self.token, self.shopName = '', ''
self.username, self.password = iusername, ipassword
self.day, self.starttime, self.endtime, self.max_site = iday, istarttime, iendtime, imax_site
self.shopNum, self.post_type = ishopnum, ipost_type
self.headers = {'Accept': 'application/json, text/plain, */*'}
self.post_dict = {'羽毛球': 'ymq', '健身中心': 'jszx', '游泳': 'yy', '风雨篮球': 'fylq', '灯光篮球': 'dglq',
'网球': 'wq', '体能中心': 'tnzx'}
def login(self):
class NoRedirHandler(urllib.request.HTTPRedirectHandler):
def http_error_302(self, req, fp, code, msg, headers):
return fp
http_error_301 = http_error_302
print('正在登录...')
# 登录请求
login_url = 'https://authserver.szpt.edu.cn/authserver/login?service=' \
'https%3A%2F%2Fydsz.szpu.edu.cn%3A443%2Fcas%2Flogin'
request = urllib.request.Request(url=login_url, method='GET')
opener = urllib.request.build_opener(urllib.request.HTTPCookieProcessor(cookiejar.CookieJar()), NoRedirHandler)
html = opener.open(request).read().decode('utf-8')
# 判断是否需要captcha
check_url = 'https://authserver.szpt.edu.cn/authserver/checkNeedCaptcha.htl?username=' + self.username
if loads(opener.open(check_url).read().decode('utf-8'))['isNeed']:
print('需要图片验证码,请前往登录页面登录后重试!\n'
'https://authserver.szpt.edu.cn/authserver/login?service='
'https%3A%2F%2Fydsz.szpu.edu.cn%3A443%2Fcas%2Flogin')
return
# 获取登录参数
execution = search('name="execution" value="(.*?)"', html, S).group(1)
aes_key = search('pwdEncryptSalt" value="(.*?)"/>', html, S).group(1)[:16].encode('utf-8')
aes_chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'
iv = ''.join([choice(aes_chars) for _ in range(16)]).encode()
raw = ''.join([choice(aes_chars) for _ in range(64)]) + self.password
amount_to_pad = AES.block_size - (len(raw) % AES.block_size)
if amount_to_pad == 0:
amount_to_pad = AES.block_size
raw = (raw + chr(amount_to_pad) * amount_to_pad).encode()
password_aes = b64encode(AES.new(aes_key, AES.MODE_CBC, iv).encrypt(raw))
params = {'username': self.username, 'password': str(password_aes)[2:-1], 'captcha': '',
'_eventId': 'submit', 'cllt': 'userNameLogin', 'dllt': 'generalLogin', 'lt': '',
'execution': execution}
# 获取重定向
result = urllib.request.Request(url=login_url, method='POST',
data=urllib.parse.urlencode(params).encode(encoding='UTF-8'))
login_url = opener.open(result).headers['Location']
login_url = opener.open(urllib.request.Request(url=login_url, method='GET')).headers['Location']
login_url = opener.open(urllib.request.Request(url=login_url, method='GET')).headers['Location']
# 获取openid
end_url = 'https://ydsz.szpu.edu.cn/easyserpClient/memberLogin/logined3?' + \
login_url[62:] + '&clubMemberCode=szzyjsxy0'
result = urllib.request.Request(url=end_url, method='GET')
self.token = loads(opener.open(result, timeout=5).read().decode('utf-8'))['data']['infa']['openid']
print('登录成功')
def send_info(self):
# 生成时间列表
timelst = []
if self.starttime < self.endtime:
for i in range(self.starttime, self.endtime):
timelst.append(str(i) + ':00' if len(str(i)) > 1 else '0' + str(i) + ':00')
else:
print('请检查时间参数')
return 2
# 获取卡ID和卡余额
url_get = 'https://ydsz.szpt.edu.cn/easyserpClient/card/getCardByUser?shopNum=' + \
self.shopNum + '&token=' + self.token
try:
carddate = loads(get(url_get, headers=self.headers, verify=False).text)['data'][0]
cardid, cardcash = carddate['cardindex'], carddate['cardcash']
except Exception as e:
print('获取校园卡数据失败,错误信息为:' + str(e))
return 2
# 构造数据
data_post, money, num = [], 0, 0
url_get = 'https://ydsz.szpt.edu.cn/easyserpClient/datediscount/getPlaceInfoByShortNameDiscount?shopNum=' + \
self.shopNum + '&dateymd=' + self.day + '&shortName=' + self.shopName + '&token=' + self.token
try:
data = loads(get(url_get, headers=self.headers, verify=False).text)['data']['placeArray']
except Exception as e:
print('获取场地信息失败,错误信息为:' + str(e))
return 2
for i in data:
for j in i['projectInfo']:
if j['state'] == 1 and j['starttime'] in timelst and num < self.max_site:
if j['money'] + money > cardcash:
break
timelst.remove(j['starttime'])
data_post.append({"day": self.day, "startTime": j["starttime"], "endTime": j["endtime"],
"placeShortName": i["projectName"]["shortname"],
"name": i["projectName"]["name"]})
money += j['money']
num += 1
if not data_post:
print('没有可用场地')
return
# 提交数据
url_post = 'https://ydsz.szpt.edu.cn/easyserpClient/place/reservationPlace'
post_data = 'token=' + self.token + '&shopNum=' + self.shopNum + \
'&fieldinfo=' + urllib.parse.quote(str(data_post)) + \
'&oldTotal=' + str(int(money)) + '.00&cardPayType=0&type=' + \
urllib.parse.quote(self.post_type) + '&offerId=&offerType=&total=' + \
str(int(money)) + '.00&premerother=&cardIndex=' + cardid + '&masterCardNum=&zengzhiMoney=0'
try:
result = loads(post(url_post, headers=self.headers, verify=False, params=post_data).text)
if result.get('msg') == 'success':
print('预定成功,共计' + str(num) + '个场地,' + str(money) + '元')
print('场地信息:')
for i in data_post:
print(i['name'] + ' ' + i['startTime'] + '-' + i['endTime'])
return 1
elif result.get('msg') == 'fail':
if '下手太晚了' in result.get('data'):
print('场地预约尚未开放')
return
else:
print('预定失败,错误信息为:' + result.get('data'))
return 2
else:
print('预定失败,错误信息为:' + str(result.get('status'), str(result.get('error'))))
return 2
except Exception as e:
print('预定失败')
print('错误信息:' + str(e))
return 2
def run(self):
flag = True
print('开始预约' + self.day[:4] + '年' + self.day[5:7] + '月' + self.day[8:] + '日' + str(self.starttime) +
'-' + str(self.endtime) + '点' + self.post_type + str(self.max_site) + '小时场地')
while True:
try:
self.login()
break
except Exception as e:
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
if '远程主机强迫关闭了一个现有的连接' in str(e):
print('请连接校园网后重试!')
else:
print('登录失败')
print('错误信息:', e)
flag = False
break
while flag:
print(datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
for _ in range(100):
if self.send_info():
flag = False
break
def win_box(self):
def func(_):
if xq_inp.get() == '西丽湖':
xm_inp['values'] = xm1
xm_inp.current(0)
else:
xm_inp['values'] = xm2
xm_inp.current(0)
def win_run():
if len(xh_inp.get()) == 8:
self.username = xh_inp.get()
else:
print('学号格式错误')
return
if len(mm_inp.get()) > 7:
self.password = mm_inp.get()
else:
print('密码格式错误')
return
tmp_time = rq_inp.get()
if len(tmp_time) == 10 and tmp_time[4] == '-' and tmp_time[7] == '-':
self.day = tmp_time
else:
print('日期格式错误')
return
if int(kssj_inp.get()) > int(jssj_inp.get()):
print('开始时间大于结束时间')
return
else:
self.starttime, self.endtime = int(kssj_inp.get()), int(jssj_inp.get())
if datetime.strptime(self.day + ' ' + str(self.starttime) + ':00:00', '%Y-%m-%d %H:%M:%S') < \
datetime.strptime(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'):
print('开始时间小于当前时间')
return
self.max_site = int(yysc_inp.get())
self.shopNum = '1001' if value1.get() == '西丽湖' else '1002'
self.post_type = value2.get()
if self.shopNum == '1001':
self.shopName = 'xlh' + self.post_dict[self.post_type]
self.post_type = '西丽湖' + self.post_type
elif self.shopNum == '1002':
self.shopName = 'lxd' + self.post_dict[self.post_type]
self.post_type = '留仙洞' + self.post_type
try:
win.update()
win.destroy()
self.run()
except Exception as e:
print('订场失败')
print('错误信息:', e)
win = Tk()
win.title("韵动深职")
width, height = 420, 130
win.geometry("{}x{}+{}+{}".format(width, height, int((win.winfo_screenwidth() - width) / 2),
int((win.winfo_screenheight() - height) / 2)))
value1, value2, value3, value4, value5 = StringVar(), StringVar(), StringVar(), StringVar(), StringVar()
xq = ['西丽湖', '留仙洞']
xm1 = ['羽毛球', '游泳', '体能中心']
xm2 = ['羽毛球', '健身中心', '游泳', '风雨篮球', '灯光篮球', '网球']
xh_text = Label(win, text="学号:")
xh_text.place(x=10, y=10)
mm_text = Label(win, text="密码:")
mm_text.place(x=10, y=50)
rq_text = Label(win, text="日期:")
rq_text.place(x=10, y=90)
xh_inp = Entry(win, width=11)
xh_inp.place(x=50, y=10)
mm_inp = Entry(win, width=11, show="*")
mm_inp.place(x=50, y=50)
rq_inp = Entry(win, width=11)
rq_inp.place(x=50, y=90)
kssj_text = Label(win, text="开始时间:")
kssj_text.place(x=140, y=10)
jssj_text = Label(win, text="结束时间:")
jssj_text.place(x=140, y=50)
yysc_text = Label(win, text="预约时长:")
yysc_text.place(x=140, y=90)
kssj_inp = ttk.Combobox(master=win, state="readonly", values=[str(i) for i in range(9, 20)], width=7,
textvariable=value3)
kssj_inp.set('9')
kssj_inp.place(x=205, y=10)
jssj_inp = ttk.Combobox(master=win, state="readonly", values=[str(i) for i in range(10, 21)], width=7,
textvariable=value4)
jssj_inp.set('10')
jssj_inp.place(x=205, y=50)
yysc_inp = ttk.Combobox(master=win, state="readonly", values=[str(i) for i in range(1, 4)], width=7,
textvariable=value5)
yysc_inp.set('1')
yysc_inp.place(x=205, y=90)
xq_test = Label(win, text="校区:")
xq_test.place(x=285, y=10)
xm_test = Label(win, text="项目:")
xm_test.place(x=285, y=50)
xq_inp = ttk.Combobox(master=win, state="readonly", textvariable=value1, values=xq, width=8)
xq_inp.set(xq[0])
xq_inp.place(x=325, y=10)
xm_inp = ttk.Combobox(master=win, state="readonly", textvariable=value2, values=xm1, width=8)
xm_inp.set(xm1[0])
xm_inp.place(x=325, y=50)
xq_inp.bind("<<ComboboxSelected>>", func)
yy_btn = Button(win, text="预约", command=win_run, width=14)
yy_btn.place(x=292, y=85)
print('请输入信息以预约')
print('请确保校园卡余额充足~')
print('!!!请注意日期格式为\"2022-11-29\"!!!')
win.mainloop()
def linux_run(self):
if self.shopNum == '1001':
self.shopName = 'xlh' + self.post_dict[self.post_type]
self.post_type = '西丽湖' + self.post_type
else:
self.shopName = 'lxd' + self.post_dict[self.post_type]
self.post_type = '留仙洞' + self.post_type
if len(self.day) != 10 or self.day[4] != '-' or self.day[7] != '-':
print('日期格式错误')
return
if self.starttime > self.endtime:
print('开始时间大于结束时间')
return
if datetime.strptime(self.day + ' ' + str(self.starttime) + ':00:00', '%Y-%m-%d %H:%M:%S') < \
datetime.strptime(datetime.now().strftime('%Y-%m-%d %H:%M:%S'), '%Y-%m-%d %H:%M:%S'):
print('开始时间小于当前时间')
return
if self.max_site > 3:
print('最多预约3小时')
return
try:
self.run()
except Exception as e:
print('订场失败')
print('错误信息:', e)
if __name__ == '__main__':
username = '' # 一网通账号
password = '' # 一网通密码
day = '2023-12-04' # 预约日期
starttime = 14 # 开始时间
endtime = 20 # 结束时间
max_site = 3 # 最多预约几小时(最多3小时)
shopNum = '1001' # 西丽湖:1001 留仙洞:1002
post_type = '羽毛球' # 羽毛球, 健身中心, 游泳, 风雨篮球, 灯光篮球, 网球, 体能中心
run_type = 1 # 1:Windows端 2:Linux端
main = Ydsz(username, password, day, starttime, endtime, max_site, shopNum, post_type)
main.win_box() if run_type == 1 else main.linux_run()
input('程序结束,按回车键退出')