├── .gitignore ├── README.md ├── UCAS_course.py ├── UCAS_course_bachelor_1.7.py ├── UCAS_course_grad_1.8.py └── dist └── UCAS_course.exe /.gitignore: -------------------------------------------------------------------------------- 1 | *.jpg 2 | *.bat 3 | *.ico 4 | *.spec 5 | 6 | build 7 | dist/*.jpg 8 | __pycache__ 9 | .cph -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UCAS_course_script 2 | A script to enroll in courses for graduate students of University of Chinese Academy of Sciences. 3 | -------------------------------------------------------------------------------- /UCAS_course.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import tkinter.messagebox 3 | import tkinter 4 | import threading 5 | import time 6 | from PIL import Image, ImageTk 7 | import re 8 | 9 | 10 | # 封装用于 post 的函数,失败返回 None 11 | def post_data(url, data = None, params = None, time_out = 3, retry = 5): 12 | for _ in range(retry): 13 | try: 14 | page = sess.post(url, data = data, params = params, timeout=time_out) 15 | return page 16 | except: 17 | pass 18 | return None 19 | 20 | def update_link(): 21 | global Avatar, link_select_course, link_save_course, link_course_manage 22 | if Avatar == '本科生': 23 | link_select_course = 'http://jwxk.ucas.ac.cn/courseManageBachelor/selectCourse' 24 | link_save_course = 'http://jwxk.ucas.ac.cn/courseManageBachelor/saveCourse' 25 | link_course_manage = 'http://jwxk.ucas.ac.cn/courseManageBachelor/main' 26 | else: 27 | link_select_course = 'http://jwxk.ucas.ac.cn/courseManage/selectCourse' 28 | link_save_course = 'http://jwxk.ucas.ac.cn/courseManage/saveCourse' 29 | link_course_manage = 'http://jwxk.ucas.ac.cn/courseManage/main' 30 | 31 | 32 | def login_jwxt(add_id_to_name = 0): 33 | page_jump = post_data('http://sep.ucas.ac.cn/portal/site/226/821') 34 | if page_jump is None: 35 | tkinter.messagebox.showerror(title = '网页超时', message = '请检查是否断网或者延迟过高') 36 | return "high delay" 37 | 38 | pattern_jwxt_id = re.compile('Identity=([\w-]*)') # 匹配数字、字母、下划线和- 39 | try: 40 | iden = re.search(pattern_jwxt_id, page_jump.text).group(1) 41 | except: 42 | tkinter.messagebox.showerror(title = '未预料的错误', message = '没有成功匹配到Identity,请及时联系维护人员') 43 | login_info['text'] = '登录失败了\t\tT_T' 44 | # print(page.text) 45 | return 46 | 47 | jump_payload = {'Identity': iden} 48 | page_jwxt = post_data('http://jwxk.ucas.ac.cn/login', data=jump_payload) 49 | if page_jwxt is None: 50 | tkinter.messagebox.showerror(title = '网页超时', message = '请检查是否断网或者延迟过高') 51 | return "high delay" 52 | 53 | pattern_student_id = re.compile('doSelectNo\?num=([\w]*)') 54 | try: 55 | list_id = re.findall(pattern_student_id, page_jwxt.text) 56 | list_id.sort() 57 | N_id =len(list_id) 58 | student_id = list_id[N_id-1] 59 | 60 | for x in list_id: 61 | print(x) 62 | 63 | student_number_payload = {'num': student_id} 64 | page_check = post_data('http://jwxk.ucas.ac.cn/doSelectNo', data = student_number_payload) 65 | if page_check is None: 66 | tkinter.messagebox.showerror(title = '网页超时', message = '请检查是否断网或者延迟过高') 67 | return "high delay" 68 | 69 | pattern_check = re.compile(' (.+?) \s*\(当前\)') 70 | id_check = re.search(pattern_check, page_check.text).group(1) 71 | if id_check != student_id: 72 | tkinter.messagebox.showerror(title = '内部错误', message = '选择学号失败,请及时联系维护人员') 73 | return "select student id fail" 74 | if add_id_to_name == 1: 75 | global name_student 76 | name_student = name_student + ' ' + student_id 77 | page_jwxt = page_check 78 | 79 | except: 80 | pass 81 | 82 | 83 | global Avatar 84 | list_bks = re.findall(re.compile('(bks)'), page_jwxt.text) 85 | print(list_bks) 86 | if len(list_bks) >0: 87 | Avatar = '本科生' 88 | else: 89 | Avatar = '研究生' 90 | 91 | #print(Avatar) 92 | update_link() 93 | global link_course_manage 94 | page_course_manage = post_data(link_course_manage) 95 | if page_course_manage is None: 96 | tkinter.messagebox.showerror(title = '网页超时', message = '请检查是否断网或者延迟过高') 97 | return "high delay" 98 | 99 | # 以下认为登录已经成功 100 | 101 | pattern_select_course_s = re.compile('\?s=(.*?)";') 102 | select_course_s = re.search(pattern_select_course_s, page_course_manage.text).group(1) 103 | 104 | pattern_deptIds = re.compile('label for="id_(\d+)"') 105 | deptIds = re.findall(pattern_deptIds, page_course_manage.text) 106 | 107 | global select_course_payload 108 | #select_course_payload = {'deptIds': deptIds} 109 | global query_s 110 | query_s = select_course_s 111 | select_course_payload = {'s': select_course_s, 'deptIds': deptIds} 112 | 113 | return 'ok' 114 | 115 | def login(event = None): 116 | user = user_input.get() 117 | pwd = pwd_input.get() 118 | code = cert_code_input.get() 119 | login_payload = {'userName': user, 'pwd': pwd, 'certCode': code, 'sb': 'sb'} 120 | 121 | global login_info, root 122 | login_info['text'] = '登录SEP...\t\t=_ = ' 123 | root.update_idletasks() 124 | 125 | # 尝试连接sep来登录 126 | page_after_login = post_data('http://sep.ucas.ac.cn/slogin', data = login_payload) 127 | if page_after_login is None: 128 | tkinter.messagebox.showerror(title = '网页超时', message = '请检查是否断网或者延迟过高') 129 | login_info['text'] = '登录失败了\t\tT_T' 130 | return 131 | # 判断是否仍停留在选课界面 132 | 133 | pattern_login_error = re.compile('
(.+?)
', re.S) 134 | try: 135 | err_type = re.search(pattern_login_error, page_after_login.text).group(1) 136 | tkinter.messagebox.showerror(title = '信息有误', message = err_type) 137 | if err_type == '密码错误': 138 | pwd_input.delete(0, tkinter.END) 139 | elif err_type == '验证码错误': 140 | cert_code_input.delete(0, tkinter.END) 141 | login_info['text'] = '登录失败了\t\tT_T' 142 | return 143 | except: 144 | pass # 信息没有错误 145 | 146 | # 尝试用正则表达式匹配姓名来判断是否成功进入sep主页面 147 | pattern_name = re.compile('"当前用户所在单位"> (.+?) (.+?)', re.S) 148 | try: 149 | global name_student 150 | name_student = re.search(pattern_name, page_after_login.text).group(2) 151 | # print(name) 152 | except: 153 | tkinter.messagebox.showerror(title = '未能成功进入 SEP', message = '请仔细检查输入的用户名、密码以及验证码') 154 | login_info['text'] = '登录失败了\t\tT_T' 155 | return 156 | 157 | login_info['text'] = '登录选课系统...\t\t>_<' 158 | root.update_idletasks() 159 | 160 | res = login_jwxt(add_id_to_name = 1) 161 | 162 | if res != 'ok': 163 | login_info['text'] = '登录失败了\t\tT_T' 164 | return 165 | login_info['text'] = '欢迎 ' + name_student + ' ^_^' 166 | 167 | # 锁住登录信息(目前来看作用只是以防万一) 168 | #select_bachlor['state'] = tkinter.DISABLED 169 | #select_graduate['state'] = tkinter.DISABLED 170 | 171 | def relogin(): 172 | page_jump = post_data('http://sep.ucas.ac.cn/appStore') 173 | if page_jump is None: 174 | tkinter.messagebox.showerror(title = '请重新登录', message = '请检查是否断网或者延迟过高') 175 | return "high delay" 176 | 177 | pattern_offline = re.compile('SEP 教育业务接入平台') 178 | if re.search(pattern_offline, page_jump.text) != None: 179 | tkinter.messagebox.showerror(title = '请重新登录', message = '看起来已经好久没有操作了') 180 | return "sign out" 181 | 182 | res = login_jwxt() 183 | return res 184 | 185 | def check_before_select(): 186 | log['text'] = '' 187 | 188 | global select_course_payload, Avatar 189 | 190 | if Avatar is None: 191 | tkinter.messagebox.showerror(title = '错误', message = '您还未登录') 192 | global auto_working # 标记是否在捡漏,0 表示不在捡漏,1 表示在捡漏 193 | auto_working = 0 194 | jianlou_switch['text'] = '捡漏' 195 | return None 196 | 197 | global link_select_course 198 | page_select_course = post_data(link_select_course, select_course_payload) 199 | if page_select_course is None: 200 | select_result['text'] = '网页超时 没有进行选课' 201 | return None 202 | 203 | off_line = re.search('你的会话已失效或身份已改变,请重新登录', page_select_course.text) 204 | if off_line: # 至少已经从选课系统中掉线 205 | global login_info, root 206 | login_info['text'] = '掉线了,自动重连中...\t=_ = ' 207 | root.update_idletasks() 208 | 209 | res = relogin() 210 | if res != 'ok': # 甚至从SEP系统中掉线 211 | init() 212 | select_result['text'] = '您已经掉线' 213 | login_info['text'] = '您已经掉线' 214 | return None 215 | else: 216 | login_info['text'] = '欢迎 ' + name_student + '\t^_^' 217 | root.update_idletasks() 218 | 219 | page_select_course = post_data(link_select_course, select_course_payload) 220 | if page_select_course is None: 221 | select_result['text'] = '网页超时 没有进行选课' 222 | return None 223 | 224 | system_closed = re.search('为了给您提供更好的服务', page_select_course.text) 225 | if system_closed: 226 | select_result['text'] = '选课系统未开放' 227 | return None 228 | 229 | select_result['text'] = '正在选课' 230 | return page_select_course 231 | 232 | def generate_log(select_result_page): 233 | pattern = re.compile('class="success">(.+?)') 234 | success_message = re.search(pattern, select_result_page.text) 235 | pattern = re.compile('class="error">(.+?)') 236 | error_message = re.search(pattern, select_result_page.text) 237 | success = 0 238 | if success_message is not None: 239 | messages = success_message.group(1).split('
') 240 | success = 1 241 | elif error_message is not None: 242 | messages = error_message.group(1).split('
') 243 | else: 244 | messages = ['403 Forbidden'] 245 | 246 | for single_message in messages: 247 | message_str = single_message 248 | if len(message_str) == 0: 249 | continue 250 | if len(message_str) > 25: 251 | message_str = message_str[:25] + '\n' + message_str[25:] 252 | if success: 253 | log_success['text'] += message_str + '\n' + sep_time['text'] + '\n' 254 | log['text'] += message_str + '\n' + sep_time['text'] + '\n' 255 | 256 | def add_course_code_to_payload(course, select_course_page): 257 | pattern = re.compile('id="courseCode_(.*?)">%s' % course) 258 | course_code = re.search(pattern, select_course_page.text) 259 | if course_code is None: 260 | log['text'] += course + ': 该课程编码不可用(可能已经选过了)' + '\n' + sep_time['text'] + '\n' 261 | return 0 262 | else: 263 | select_course_payload['sids'].append(course_code.group(1)) 264 | return 1 265 | 266 | def list_split(list): 267 | list = re.split('[,,]',list) 268 | res = [] 269 | for x in list: 270 | x = x.strip() 271 | if x != '': 272 | res.append(x) 273 | return res 274 | 275 | def get_csrftoken(select_course_page): 276 | global select_course_payload 277 | pattern_get_csrftoken = re.compile('name="_csrftoken" value="(.*?)"') 278 | value = re.search(pattern_get_csrftoken, select_course_page.text).group(1) 279 | select_course_payload['_csrftoken'] = value 280 | 281 | 282 | def select_separately(event): 283 | select_course_page = check_before_select() 284 | if select_course_page is None: 285 | return 286 | 287 | course_list = list_split(course_input_separate.get()) 288 | 289 | global Avatar, link_save_course, link_select_course 290 | 291 | sess.headers.update({"Referer": link_select_course + "?s=" + query_s}) 292 | for course in course_list: 293 | select_course_page = check_before_select() 294 | select_course_payload['sids'] = [] 295 | if add_course_code_to_payload(course, select_course_page) == 0: 296 | continue 297 | 298 | get_csrftoken(select_course_page) 299 | select_result_page = post_data(link_save_course, select_course_payload) 300 | if select_result_page is None: 301 | log['text'] += course + ': 网页超时'+' \n ' + sep_time['text'] + '\n' 302 | else: 303 | generate_log(select_result_page) 304 | del select_course_payload['_csrftoken'] 305 | 306 | del sess.headers['Referer'] 307 | select_result['text'] = '选课完成' 308 | 309 | def select_together(event): 310 | select_course_page = check_before_select() 311 | if select_course_page is None: 312 | return 313 | 314 | course_list = list_split(course_input.get()) 315 | 316 | select_course_payload['sids'] = [] 317 | for course in course_list: 318 | add_course_code_to_payload(course, select_course_page) 319 | 320 | if len(select_course_payload['sids']) == 0: 321 | select_result['text'] = '课程代码均不可用' 322 | return 323 | 324 | global Avatar, link_save_course, link_select_course, link_course_manage 325 | 326 | get_csrftoken(select_course_page) 327 | sess.headers.update({"Referer": link_select_course + "?s=" + query_s}) 328 | 329 | select_result_page = post_data(link_save_course + "?s=" + query_s, data = select_course_payload) 330 | 331 | del select_course_payload['_csrftoken'] 332 | del sess.headers['Referer'] 333 | 334 | #print(result_page.text) 335 | if select_result_page is None: 336 | select_result['text'] = '网页超时 没有进行选课' 337 | else: 338 | generate_log(select_result_page) 339 | select_result['text'] = '选课完成' 340 | 341 | 342 | def get_time(): 343 | while True: 344 | try: 345 | current_time = requests.get('http://jwxk.ucas.ac.cn/courseManage/main', timeout=3) 346 | current_time = current_time.headers 347 | current_time = current_time['Date'] 348 | hour = current_time[17:19] 349 | minute = current_time[20:22] 350 | second = current_time[23:25] 351 | hour = (int(hour) + 8) % 24 352 | time_str = str(hour) + ':' + minute + ':' + second 353 | sep_time['text'] = time_str 354 | time.sleep(1) 355 | root.update_idletasks() 356 | except: 357 | pass 358 | 359 | def auto_select(): 360 | global auto_working 361 | global login_mark 362 | 363 | while True: 364 | if auto_working: 365 | select_separately(None) 366 | time.sleep(1) 367 | 368 | 369 | def auto_switch(event): 370 | global auto_working 371 | 372 | if auto_working == 0: 373 | tkinter.messagebox.showinfo(title = '提示', 374 | message = '1.请先使用“分开选”功能,确认提示信息为“超过限选人数”(而无其他错误)后再使用此功能\n' 375 | '2.此模式每1s自动进行一次“分开选”(温馨提示:持续过长有风险)\n' 376 | '3.如若中途掉线,需要自己手动重新登录') 377 | jianlou_switch['text'] = '停止' 378 | else: 379 | jianlou_switch['text'] = '捡漏' 380 | auto_working = 1 - auto_working 381 | 382 | 383 | def download_image_file(event): 384 | global sess, login_info 385 | 386 | login_info['text'] = '' 387 | try: 388 | html = sess.get('http://sep.ucas.ac.cn/randomcode.jpg', timeout = 3) 389 | except: 390 | login_info['text'] = '网页超时 请重新获取验证码' 391 | return 392 | 393 | fp = open("certcode.jpg", 'wb') 394 | fp.write(html.content) 395 | fp.close() 396 | 397 | global cert_photo, show_pic 398 | cert_img = Image.open("certcode.jpg") 399 | cert_img = cert_img.resize((100, 25), Image.ANTIALIAS) # 调整大小 Image.ANTIALIAS 抗锯齿 400 | cert_photo = ImageTk.PhotoImage(cert_img) 401 | show_pic['image'] = cert_photo 402 | 403 | cert_code_input.delete(0, tkinter.END) 404 | 405 | # 初始化 406 | def init(): 407 | # 全局变量 408 | global select_course_payload # 用于选课的 payload,记录用于选课的 cid 和 要选的课程编号 409 | select_course_payload = None 410 | 411 | global auto_working # 标记是否在捡漏,0 表示不在捡漏,1 表示在捡漏 412 | auto_working = 0 413 | jianlou_switch['text'] = '捡漏' 414 | 415 | global sess # 全局session 416 | sess = requests.session() 417 | sess.headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36 Edg/92.0.902.84'}) # 给 seesion 做伪装,通过浏览器检测 418 | 419 | global Avatar # 标明用本科生/研究生身份登录 420 | Avatar = None 421 | 422 | download_image_file(None) 423 | 424 | #select_bachlor['state'] = tkinter.NORMAL 425 | #select_graduate['state'] = tkinter.NORMAL 426 | 427 | 428 | def sign_out(): 429 | global Avatar 430 | if Avatar == None: 431 | tkinter.messagebox.showerror(title = 'Error', message = '您尚未登录') 432 | return 433 | init() 434 | login_info['text'] = '成功下线' 435 | 436 | if __name__ == "__main__": 437 | global root 438 | root = tkinter.Tk() 439 | root.title("UCAS_course") 440 | root.geometry('615x580') 441 | root.resizable(width = False, height = False) 442 | 443 | menubar = tkinter.Menu(root) 444 | menubar.add_command(label = "下线", command = sign_out) 445 | root.config(menu = menubar) 446 | 447 | sep_time = tkinter.Label(root, font = ('Calibri', '10')) 448 | sep_time.grid(row = 0, column = 1, sticky = tkinter.E) #紧贴右侧 449 | 450 | thread_time = threading.Thread(target = get_time) 451 | thread_time.setDaemon(True) 452 | thread_time.start() 453 | 454 | global login_info 455 | login_info = tkinter.Label(root, text = '') 456 | login_info.grid(row = 6, column = 0, sticky = tkinter.W) #紧贴左侧 457 | login_info['font'] = ('Calibri', '14') 458 | 459 | tkinter.Label(root, text = '用户名(同sep)', font = ('Calibri', '14')).grid(row = 0, column = 0, sticky = tkinter.W) 460 | user_input = tkinter.Entry(root) 461 | user_input.grid(row = 1, column = 0, sticky = tkinter.W) 462 | user_input['font'] = ('Calibri', '14') 463 | user_input['width'] = 30 464 | 465 | tkinter.Label(root, text = '密码', font=('Calibri', '14')).grid(row = 0, column = 1, sticky = tkinter.W) 466 | pwd_input = tkinter.Entry(root) 467 | pwd_input['show'] = '*' 468 | pwd_input['width'] = 30 469 | pwd_input.grid(row = 1, column = 1, sticky = tkinter.W) 470 | pwd_input['font'] = ('Calibri', '14') 471 | pwd_input.bind('', login) 472 | 473 | # 验证码 Frame 474 | frame_cert = tkinter.Frame(master = root, bd = 0, relief = tkinter.RAISED, width = 1) 475 | frame_cert.grid(row = 2, column = 0, sticky = tkinter.W) 476 | # text 477 | tkinter.Label(master = frame_cert, text = '验证码', font = ('Calibri', '14')).pack(side = tkinter.LEFT, padx = 0) 478 | # input entry 479 | global cert_code_input 480 | cert_code_input = tkinter.Entry(master = frame_cert) 481 | cert_code_input['width'] = 5 482 | cert_code_input.pack(side = tkinter.LEFT, padx = 4) 483 | cert_code_input['font'] = ('Calibri', '14') 484 | cert_code_input.bind('', login) 485 | # picture 486 | global show_pic 487 | show_pic = tkinter.Label(master = frame_cert) 488 | show_pic.pack(side = tkinter.LEFT, padx = 4) 489 | # buttom 490 | get_pic = tkinter.Button(master = frame_cert, text = '刷新') 491 | get_pic.pack(side = tkinter.LEFT, padx = 4) 492 | get_pic['width'] = 5 493 | get_pic['font'] = ('Calibri', '14') 494 | get_pic.bind('', download_image_file) 495 | get_pic.bind('', download_image_file) 496 | 497 | # 选择身份 498 | ''' 499 | global avatar_input 500 | avatar_input = tkinter.StringVar() # 定义变量记录所选身份 501 | avatar_input.set('本科生') 502 | frame_avatar = tkinter.Frame(master = root, bd = 0, relief = tkinter.RAISED, width = 1) 503 | frame_avatar.grid(row = 2, column = 1, sticky = tkinter.W) 504 | select_bachlor = tkinter.Radiobutton(frame_avatar, text = '本科生', variable = avatar_input, value = '本科生') # 默认设置本科生 505 | select_bachlor.pack(side = tkinter.LEFT, padx = 4) 506 | select_bachlor.bind('', login) 507 | select_graduate = tkinter.Radiobutton(frame_avatar, text = '研究生', variable = avatar_input, value = '研究生') 508 | select_graduate.pack(side = tkinter.LEFT, padx = 4) 509 | select_graduate.bind('', login) 510 | #print(avatar_input.get()) 511 | ''' 512 | 513 | login_button = tkinter.Button(root, text = '登 录') 514 | login_button['width'] = 6 515 | login_button['font'] = ('Calibri', '14') 516 | login_button.grid(row = 6, column = 1, sticky = tkinter.E) 517 | login_button.bind('', login) 518 | login_button.bind('', login) 519 | 520 | select_result = tkinter.Label(root, text = '') 521 | select_result.grid(row = 9, sticky = tkinter.W) 522 | select_result['font'] = ('Calibri', '14') 523 | 524 | tkinter.Label(root, text = '课程编码(一起选) 用逗号分隔', font = ('Calibri', '14')).grid(row = 7, column = 0, sticky = tkinter.W) 525 | course_input = tkinter.Entry(root) 526 | course_input['width'] = 30 527 | course_input.grid(row = 8, column = 0, sticky = tkinter.W) 528 | course_input['font'] = ('Calibri', '14') 529 | course_input.bind('', select_together) 530 | 531 | tkinter.Label(root, text = '课程编码(分开选) 用逗号分隔', font=('Calibri', '14')).grid(row = 7, column = 1, sticky = tkinter.W) 532 | course_input_separate = tkinter.Entry(root) 533 | course_input_separate['width'] = 30 534 | course_input_separate.grid(row = 8, column = 1, sticky = tkinter.W) 535 | course_input_separate['font'] = ('Calibri', '14') 536 | course_input_separate.bind('', select_separately) 537 | 538 | course_choose = tkinter.Button(root, text = '一起选') 539 | course_choose.bind('', select_together) 540 | course_choose['font'] = ('Calibri', '14') 541 | course_choose['width'] = 6 542 | course_choose.grid(row = 9, column = 0, sticky = tkinter.E) 543 | 544 | course_choose = tkinter.Button(root, text = '分开选') 545 | course_choose.bind('', select_separately) 546 | course_choose['font'] = ('Calibri', '14') 547 | course_choose['width'] = 6 548 | course_choose.grid(row = 9, column = 1, sticky = tkinter.E) 549 | 550 | jianlou_switch = tkinter.Button(root, text = '捡 漏') 551 | jianlou_switch.bind('', auto_switch) 552 | jianlou_switch['font'] = ('Calibri', '14') 553 | jianlou_switch['width'] = 6 554 | jianlou_switch.grid(row = 9, column = 1, sticky = tkinter.W) 555 | 556 | tkinter.Label(root, text = 'Log:', font=('Calibri', '14')).grid(row = 11, column = 0, sticky = tkinter.W) 557 | log = tkinter.Label(root, anchor = 'nw', justify = 'left', background = 'white', relief = 'sunken', height = 21, width = 50, 558 | borderwidth = 2) 559 | log.grid(row = 12, column = 0, sticky = tkinter.W) 560 | log['font'] = ('Calibri', '9') 561 | 562 | tkinter.Label(root, text = 'Log_Success:', font=('Calibri', '14')).grid(row = 11, column = 1, sticky = tkinter.W) 563 | log_success = tkinter.Label(root, anchor = 'nw', justify = 'left', background = 'white', relief = 'sunken', height = 21, 564 | width = 50, borderwidth = 2) 565 | log_success.grid(row = 12, column = 1, sticky = tkinter.W) 566 | log_success['font'] = ('Calibri', '9') 567 | 568 | init() 569 | thread_auto_select = threading.Thread(target = auto_select) 570 | thread_auto_select.setDaemon(True) 571 | thread_auto_select.start() 572 | root.mainloop() 573 | -------------------------------------------------------------------------------- /UCAS_course_bachelor_1.7.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import tkinter.messagebox 3 | import tkinter 4 | import threading 5 | import time 6 | from PIL import Image, ImageTk 7 | import re 8 | 9 | 10 | def post_data(url, data=None, time_out=3, retry=5): 11 | for _ in range(retry): 12 | try: 13 | page = sess.post(url, data=data, timeout=time_out) 14 | return page 15 | except: 16 | pass 17 | return None 18 | 19 | 20 | def check_online(): 21 | log['text'] = '' 22 | 23 | if select_course_payload is None: 24 | tkinter.messagebox.showerror(title='错误', message='您还未登录') 25 | return None 26 | 27 | page = post_data('http://jwxk.ucas.ac.cn/courseManageBachelor/selectCourse', select_course_payload) 28 | if page is None: 29 | select_result['text'] = '网页超时 没有进行选课' 30 | return None 31 | 32 | off_line = re.search('你的会话已失效或身份已改变,请重新登录', page.text) 33 | if off_line: 34 | select_result['text'] = '您已经掉线' 35 | login_info['text'] = '您已经掉线' 36 | return None 37 | 38 | system_closed = re.search('为了给您提供更好的服务', page.text) 39 | if system_closed: 40 | select_result['text'] = '选课系统未开放' 41 | return None 42 | 43 | select_result['text'] = '正在选课' 44 | return page 45 | 46 | 47 | def generate_log(select_result_page): 48 | pattern = re.compile('class="success">(.+?)') 49 | success_message = re.search(pattern, select_result_page.text) 50 | pattern = re.compile('class="error">(.+?)') 51 | error_message = re.search(pattern, select_result_page.text) 52 | success = 0 53 | if success_message is not None: 54 | messages = success_message.group(1).split('
') 55 | success = 1 56 | elif error_message is not None: 57 | messages = error_message.group(1).split('
') 58 | else: 59 | messages = ['403 Forbidden'] 60 | 61 | for single_message in messages: 62 | message_str = single_message 63 | if len(message_str) == 0: 64 | continue 65 | if len(message_str) > 25: 66 | message_str = message_str[:25] + '\n' + message_str[25:] 67 | if success: 68 | log_success['text'] += message_str + '\n' + sep_time['text'] + '\n' 69 | log['text'] += message_str + '\n' + sep_time['text'] + '\n' 70 | 71 | 72 | def add_course_code_to_payload(course, select_course_page): 73 | pattern = re.compile('id="courseCode_(.*?)">%s' % course) 74 | course_code = re.search(pattern, select_course_page.text) 75 | if course_code is None: 76 | log['text'] += course + ': 该课程编码不可用(可能已经选过了)' + '\n' + sep_time['text'] + '\n' 77 | return 1 78 | else: 79 | select_course_payload['sids'].append(course_code.group(1)) 80 | return 0 81 | 82 | 83 | def select_separately(event): 84 | select_course_page = check_online() 85 | if select_course_page is None: 86 | return 87 | 88 | course_list = course_input_separate.get() 89 | course_list = course_list.split() 90 | for course in course_list: 91 | select_course_payload['sids'] = [] 92 | if add_course_code_to_payload(course, select_course_page): 93 | continue 94 | 95 | select_result_page = post_data('http://jwxk.ucas.ac.cn/courseManageBachelor/saveCourse', select_course_payload) 96 | if select_result_page is None: 97 | log['text'] += course + ': 网页超时'+' \n ' + sep_time['text'] + '\n' 98 | else: 99 | generate_log(select_result_page) 100 | 101 | select_result['text'] = '选课完成' 102 | 103 | 104 | def select_together(event): 105 | select_course_page = check_online() 106 | if select_course_page is None: 107 | return 108 | 109 | course_list = course_input.get() 110 | course_list = course_list.split() 111 | select_course_payload['sids'] = [] 112 | for course in course_list: 113 | add_course_code_to_payload(course, select_course_page) 114 | 115 | if len(select_course_payload['sids']) == 0: 116 | select_result['text'] = '课程代码均不可用' 117 | return 118 | 119 | select_result_page = post_data('http://jwxk.ucas.ac.cn/courseManageBachelor/saveCourse', select_course_payload) 120 | if select_result_page is None: 121 | select_result['text'] = '网页超时 没有进行选课' 122 | else: 123 | generate_log(select_result_page) 124 | select_result['text'] = '选课完成' 125 | 126 | 127 | def login(event): 128 | user = user_input.get() 129 | pwd = pwd_input.get() 130 | code = cert_code_input.get() 131 | login_payload = {'userName': user, 'pwd': pwd, 'certCode': code, 'sb': 'sb'} 132 | 133 | login_info['text'] = '正在登录' 134 | root.update_idletasks() 135 | 136 | page = post_data('http://sep.ucas.ac.cn/slogin', data=login_payload) 137 | if page is None: 138 | login_info['text'] = '网页超时 请重新登录' 139 | return 140 | 141 | pattern = re.compile(' (.+?)', re.S) 142 | try: 143 | name = re.search(pattern, page.text).group(1) 144 | except: 145 | login_info['text'] = '信息有误' 146 | return 147 | 148 | page = post_data('http://sep.ucas.ac.cn/portal/site/226/821') 149 | if page is None: 150 | login_info['text'] = '网页超时 请重新登录' 151 | return 152 | 153 | pattern = re.compile('Identity=([\w-]*)') 154 | try: 155 | iden = re.search(pattern, page.text).group(1) 156 | except: 157 | login_info['text'] = '没有成功匹配到Identity,请及时联系作者' 158 | return 159 | 160 | login_info['text'] = '正在跳转' 161 | root.update_idletasks() 162 | 163 | jump_payload = {'Identity': iden} 164 | page = post_data('http://jwxk.ucas.ac.cn/login', data=jump_payload) 165 | if page is None: 166 | login_info['text'] = '网页超时 请重新登录' 167 | return 168 | 169 | pattern = re.compile('"_id_1">  (.+?)') 170 | try: 171 | student_number = re.search(pattern, page.text).group(1) 172 | student_number_payload = {'num': student_number, 'sb': 'y'} 173 | page = post_data('http://jwxk.ucas.ac.cn/doSelectNo', data=student_number_payload) 174 | if page is None: 175 | login_info['text'] = '网页超时 请重新登录' 176 | return 177 | except: 178 | pass 179 | 180 | page = post_data('http://jwxk.ucas.ac.cn/courseManageBachelor/main') 181 | if page is None: 182 | login_info['text'] = '网页超时 请重新登录' 183 | return 184 | pattern = re.compile('\?s=(.*?)";') 185 | select_course_s = re.search(pattern, page.text).group(1) 186 | pattern = re.compile('label for="id_(\d+)"') 187 | deptIds = re.findall(pattern, page.text) 188 | global select_course_payload 189 | select_course_payload = {'s': select_course_s, 'deptIds': deptIds, 'sb': 'y'} 190 | login_info['text'] = '登陆成功 ' + name 191 | 192 | 193 | def get_time(): 194 | while True: 195 | try: 196 | current_time = requests.get('http://jwxk.ucas.ac.cn/courseManageBachelor/main', timeout=3) 197 | current_time = current_time.headers 198 | current_time = current_time['Date'] 199 | hour = current_time[17:19] 200 | minute = current_time[20:22] 201 | second = current_time[23:25] 202 | hour = int(hour) + 8 203 | time_str = str(hour) + ':' + minute + ':' + second 204 | sep_time['text'] = time_str 205 | time.sleep(1) 206 | root.update_idletasks() 207 | except: 208 | pass 209 | 210 | 211 | def auto_select(): 212 | global auto_working 213 | while True: 214 | if auto_working and login_info['text'] != '您已经掉线': 215 | select_separately(None) 216 | time.sleep(1) 217 | 218 | 219 | def auto_switch(event): 220 | global auto_working 221 | if auto_working == 0: 222 | tkinter.messagebox.showinfo(title='提示', 223 | message='1.请先使用“分开选”功能,确认提示信息为“超过限选人数”(而无其他错误)后再使用此功能\n' 224 | '2.此模式每1s自动进行一次“分开选”\n' 225 | '3.如若中途掉线,需要自己手动重新登录') 226 | jianlou_switch['text'] = '停止' 227 | else: 228 | jianlou_switch['text'] = '捡漏' 229 | auto_working = 1 - auto_working 230 | 231 | 232 | def download_image_file(event): 233 | global sess 234 | sess = requests.session() 235 | login_info['text'] = '' 236 | try: 237 | html = sess.get('http://sep.ucas.ac.cn/changePic', timeout=3) 238 | except: 239 | login_info['text'] = '网页超时 请重新获取验证码' 240 | return 241 | 242 | fp = open("certcode.jpg", 'wb') 243 | fp.write(html.content) 244 | fp.close() 245 | global cert_photo 246 | cert_img = Image.open("certcode.jpg") 247 | cert_photo = ImageTk.PhotoImage(cert_img) 248 | show_pic['image'] = cert_photo 249 | 250 | 251 | if __name__ == "__main__": 252 | auto_working = 0 253 | login_check = 0 254 | root = tkinter.Tk() 255 | root.title("UCAS_course_grad 1.7 by wyf && YaoBIG QQ:751076061") 256 | root.geometry('620x640') 257 | root.resizable(width=False, height=False) 258 | 259 | sep_time = tkinter.Label(root, font=('Calibri', '10')) 260 | sep_time.grid(row=0, column=1, sticky=tkinter.E) 261 | 262 | thread_1 = threading.Thread(target=get_time) 263 | thread_1.setDaemon(True) 264 | thread_1.start() 265 | 266 | thread_2 = threading.Thread(target=auto_select) 267 | thread_2.setDaemon(True) 268 | thread_2.start() 269 | 270 | login_info = tkinter.Label(root, text='') 271 | login_info.grid(row=6, column=0, sticky=tkinter.W) 272 | login_info['font'] = ('Calibri', '14') 273 | 274 | select_result = tkinter.Label(root, text='') 275 | select_result.grid(row=9, sticky=tkinter.W) 276 | select_result['font'] = ('Calibri', '14') 277 | 278 | tkinter.Label(root, text='用户名(同sep)', font=('Calibri', '14')).grid(row=0, column=0, sticky=tkinter.W) 279 | user_input = tkinter.Entry(root) 280 | user_input.grid(row=1, column=0, sticky=tkinter.W) 281 | user_input['font'] = ('Calibri', '14') 282 | user_input['width'] = 30 283 | 284 | tkinter.Label(root, text='密码', font=('Calibri', '14')).grid(row=0, column=1, sticky=tkinter.W) 285 | pwd_input = tkinter.Entry(root) 286 | pwd_input['show'] = '*' 287 | pwd_input['width'] = 30 288 | pwd_input.grid(row=1, column=1, sticky=tkinter.W) 289 | pwd_input['font'] = ('Calibri', '14') 290 | pwd_input.bind('', login) 291 | 292 | get_pic = tkinter.Button(root, text='重新获取验证码') 293 | get_pic['width'] = 12 294 | get_pic.grid(row=5, column=1, sticky=tkinter.W) 295 | get_pic['font'] = ('Calibri', '14') 296 | get_pic.bind('', download_image_file) 297 | 298 | show_pic = tkinter.Label(root) 299 | show_pic.grid(row=5, column=1, sticky=tkinter.E) 300 | download_image_file(None) 301 | 302 | tkinter.Label(root, text='验证码', font=('Calibri', '14')).grid(row=2, column=0, sticky=tkinter.W) 303 | 304 | cert_code_input = tkinter.Entry(root) 305 | cert_code_input['width'] = 30 306 | cert_code_input.grid(row=5, column=0, sticky=tkinter.W) 307 | cert_code_input['font'] = ('Calibri', '14') 308 | cert_code_input.bind('', login) 309 | 310 | login_button = tkinter.Button(root, text='登 录') 311 | login_button['width'] = 6 312 | login_button['font'] = ('Calibri', '14') 313 | login_button.grid(row=6, column=1, sticky=tkinter.E) 314 | login_button.bind('', login) 315 | 316 | tkinter.Label(root, text='课程编码(一起选) 用空格连接', font=('Calibri', '14')).grid(row=7, column=0, sticky=tkinter.W) 317 | course_input = tkinter.Entry(root) 318 | course_input['width'] = 30 319 | course_input.grid(row=8, column=0, sticky=tkinter.W) 320 | course_input['font'] = ('Calibri', '14') 321 | course_input.bind('', select_together) 322 | 323 | tkinter.Label(root, text='课程编码(分开选) 用空格连接', font=('Calibri', '14')).grid(row=7, column=1, sticky=tkinter.W) 324 | course_input_separate = tkinter.Entry(root) 325 | course_input_separate['width'] = 30 326 | course_input_separate.grid(row=8, column=1, sticky=tkinter.W) 327 | course_input_separate['font'] = ('Calibri', '14') 328 | course_input_separate.bind('', select_separately) 329 | 330 | course_choose = tkinter.Button(root, text='一起选') 331 | course_choose.bind('', select_together) 332 | course_choose['font'] = ('Calibri', '14') 333 | course_choose['width'] = 6 334 | course_choose.grid(row=9, column=0, sticky=tkinter.E) 335 | 336 | course_choose = tkinter.Button(root, text='分开选') 337 | course_choose.bind('', select_separately) 338 | course_choose['font'] = ('Calibri', '14') 339 | course_choose['width'] = 6 340 | course_choose.grid(row=9, column=1, sticky=tkinter.E) 341 | 342 | jianlou_switch = tkinter.Button(root, text='捡 漏') 343 | jianlou_switch.bind('', auto_switch) 344 | jianlou_switch['font'] = ('Calibri', '14') 345 | jianlou_switch['width'] = 6 346 | jianlou_switch.grid(row=9, column=1, sticky=tkinter.W) 347 | 348 | tkinter.Label(root, text='Log:', font=('Calibri', '14')).grid(row=11, column=0, sticky=tkinter.W) 349 | log = tkinter.Label(root, anchor='nw', justify='left', background='white', relief='sunken', height=21, width=50, 350 | borderwidth=2) 351 | log.grid(row=12, column=0, sticky=tkinter.W) 352 | log['font'] = ('Calibri', '9') 353 | 354 | tkinter.Label(root, text='Log_Success:', font=('Calibri', '14')).grid(row=11, column=1, sticky=tkinter.W) 355 | log_success = tkinter.Label(root, anchor='nw', justify='left', background='white', relief='sunken', height=21, 356 | width=50, borderwidth=2) 357 | log_success.grid(row=12, column=1, sticky=tkinter.W) 358 | log_success['font'] = ('Calibri', '9') 359 | 360 | root.mainloop() 361 | 362 | -------------------------------------------------------------------------------- /UCAS_course_grad_1.8.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import tkinter.messagebox 3 | import tkinter 4 | import threading 5 | import time 6 | from PIL import Image, ImageTk 7 | import re 8 | 9 | 10 | def post_data(url, data=None, time_out=3, retry=5): 11 | for _ in range(retry): 12 | try: 13 | page = sess.post(url, data=data, timeout=time_out) 14 | return page 15 | except: 16 | pass 17 | return None 18 | 19 | 20 | def check_online(): 21 | log['text'] = '' 22 | 23 | if select_course_payload is None: 24 | tkinter.messagebox.showerror(title='错误', message='您还未登录') 25 | return None 26 | 27 | page = post_data('http://jwxk.ucas.ac.cn/courseManage/selectCourse', select_course_payload) 28 | if page is None: 29 | select_result['text'] = '网页超时 没有进行选课' 30 | return None 31 | 32 | off_line = re.search('你的会话已失效或身份已改变,请重新登录', page.text) 33 | if off_line: 34 | select_result['text'] = '您已经掉线' 35 | login_info['text'] = '您已经掉线' 36 | return None 37 | 38 | system_closed = re.search('为了给您提供更好的服务', page.text) 39 | if system_closed: 40 | select_result['text'] = '选课系统未开放' 41 | return None 42 | 43 | select_result['text'] = '正在选课' 44 | return page 45 | 46 | 47 | def generate_log(select_result_page): 48 | pattern = re.compile('class="success">(.+?)') 49 | success_message = re.search(pattern, select_result_page.text) 50 | pattern = re.compile('class="error">(.+?)') 51 | error_message = re.search(pattern, select_result_page.text) 52 | success = 0 53 | if success_message is not None: 54 | messages = success_message.group(1).split('
') 55 | success = 1 56 | elif error_message is not None: 57 | messages = error_message.group(1).split('
') 58 | else: 59 | messages = ['403 Forbidden'] 60 | 61 | for single_message in messages: 62 | message_str = single_message 63 | if len(message_str) == 0: 64 | continue 65 | if len(message_str) > 25: 66 | message_str = message_str[:25] + '\n' + message_str[25:] 67 | if success: 68 | log_success['text'] += message_str + '\n' + sep_time['text'] + '\n' 69 | log['text'] += message_str + '\n' + sep_time['text'] + '\n' 70 | 71 | 72 | def add_course_code_to_payload(course, select_course_page): 73 | pattern = re.compile('id="courseCode_(.*?)">%s' % course) 74 | course_code = re.search(pattern, select_course_page.text) 75 | if course_code is None: 76 | log['text'] += course + ': 该课程编码不可用(可能已经选过了)' + '\n' + sep_time['text'] + '\n' 77 | return 1 78 | else: 79 | select_course_payload['sids'].append(course_code.group(1)) 80 | return 0 81 | 82 | 83 | def select_separately(event): 84 | select_course_page = check_online() 85 | if select_course_page is None: 86 | return 87 | 88 | course_list = course_input_separate.get() 89 | course_list = course_list.split(',') 90 | for course in course_list: 91 | select_course_payload['sids'] = [] 92 | if add_course_code_to_payload(course, select_course_page): 93 | continue 94 | 95 | select_result_page = post_data('http://jwxk.ucas.ac.cn/courseManage/saveCourse', select_course_payload) 96 | if select_result_page is None: 97 | log['text'] += course + ': 网页超时'+' \n ' + sep_time['text'] + '\n' 98 | else: 99 | generate_log(select_result_page) 100 | 101 | select_result['text'] = '选课完成' 102 | 103 | 104 | def select_together(event): 105 | select_course_page = check_online() 106 | if select_course_page is None: 107 | return 108 | 109 | course_list = course_input.get() 110 | course_list = course_list.split(',') 111 | select_course_payload['sids'] = [] 112 | for course in course_list: 113 | add_course_code_to_payload(course, select_course_page) 114 | 115 | if len(select_course_payload['sids']) == 0: 116 | select_result['text'] = '课程代码均不可用' 117 | return 118 | 119 | select_result_page = post_data('http://jwxk.ucas.ac.cn/courseManage/saveCourse', select_course_payload) 120 | if select_result_page is None: 121 | select_result['text'] = '网页超时 没有进行选课' 122 | else: 123 | generate_log(select_result_page) 124 | select_result['text'] = '选课完成' 125 | 126 | 127 | def login(event): 128 | user = user_input.get() 129 | pwd = pwd_input.get() 130 | code = cert_code_input.get() 131 | login_payload = {'userName': user, 'pwd': pwd, 'certCode': code, 'sb': 'sb'} 132 | 133 | login_info['text'] = '正在登录' 134 | root.update_idletasks() 135 | 136 | page = post_data('http://sep.ucas.ac.cn/slogin', data=login_payload) 137 | if page is None: 138 | login_info['text'] = '网页超时 请重新登录' 139 | return 140 | 141 | pattern = re.compile(' (.+?)', re.S) 142 | try: 143 | name = re.search(pattern, page.text).group(1) 144 | except: 145 | login_info['text'] = '信息有误' 146 | return 147 | 148 | page = post_data('http://sep.ucas.ac.cn/portal/site/226/821') 149 | if page is None: 150 | login_info['text'] = '网页超时 请重新登录' 151 | return 152 | 153 | pattern = re.compile('Identity=([\w-]*)') 154 | try: 155 | iden = re.search(pattern, page.text).group(1) 156 | except: 157 | login_info['text'] = '没有成功匹配到Identity,请及时联系作者' 158 | return 159 | 160 | login_info['text'] = '正在跳转' 161 | root.update_idletasks() 162 | 163 | jump_payload = {'Identity': iden} 164 | page = post_data('http://jwxk.ucas.ac.cn/login', data=jump_payload) 165 | if page is None: 166 | login_info['text'] = '网页超时 请重新登录' 167 | return 168 | 169 | pattern = re.compile(' (.+?) \s*\(当前\)') 170 | try: 171 | student_number = re.search(pattern, page.text).group(1) 172 | student_number_payload = {'num': student_number} 173 | page = post_data('http://jwxk.ucas.ac.cn/doSelectNo', data=student_number_payload) 174 | if page is None: 175 | login_info['text'] = '网页超时 请重新登录' 176 | return 177 | except: 178 | pass 179 | 180 | page = post_data('http://jwxk.ucas.ac.cn/courseManage/main') 181 | if page is None: 182 | login_info['text'] = '网页超时 请重新登录' 183 | return 184 | pattern = re.compile('\?s=(.*?)";') 185 | select_course_s = re.search(pattern, page.text).group(1) 186 | pattern = re.compile('label for="id_(\d+)"') 187 | deptIds = re.findall(pattern, page.text) 188 | global select_course_payload 189 | select_course_payload = {'s': select_course_s, 'deptIds': deptIds} 190 | login_info['text'] = '登陆成功 ' + name 191 | 192 | 193 | def get_time(): 194 | while True: 195 | try: 196 | current_time = requests.get('http://jwxk.ucas.ac.cn/courseManage/main', timeout=3) 197 | current_time = current_time.headers 198 | current_time = current_time['Date'] 199 | hour = current_time[17:19] 200 | minute = current_time[20:22] 201 | second = current_time[23:25] 202 | hour = int(hour) + 8 203 | time_str = str(hour) + ':' + minute + ':' + second 204 | sep_time['text'] = time_str 205 | time.sleep(1) 206 | root.update_idletasks() 207 | except: 208 | pass 209 | 210 | 211 | def auto_select(): 212 | global auto_working 213 | while True: 214 | if auto_working and login_info['text'] != '您已经掉线': 215 | select_separately(None) 216 | time.sleep(1) 217 | 218 | 219 | def auto_switch(event): 220 | global auto_working 221 | if auto_working == 0: 222 | tkinter.messagebox.showinfo(title='提示', 223 | message='1.请先使用“分开选”功能,确认提示信息为“超过限选人数”(而无其他错误)后再使用此功能\n' 224 | '2.此模式每1s自动进行一次“分开选”(温馨提示:持续过长有风险)\n' 225 | '3.如若中途掉线,需要自己手动重新登录') 226 | jianlou_switch['text'] = '停止' 227 | else: 228 | jianlou_switch['text'] = '捡漏' 229 | auto_working = 1 - auto_working 230 | 231 | 232 | def download_image_file(event): 233 | global sess 234 | sess = requests.session() 235 | sess.headers.update({'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4261.0 Safari/537.36'}) 236 | 237 | login_info['text'] = '' 238 | try: 239 | html = sess.get('http://sep.ucas.ac.cn/changePic', timeout=3) 240 | except: 241 | login_info['text'] = '网页超时 请重新获取验证码' 242 | return 243 | 244 | fp = open("certcode.jpg", 'wb') 245 | fp.write(html.content) 246 | fp.close() 247 | global cert_photo 248 | cert_img = Image.open("certcode.jpg") 249 | cert_photo = ImageTk.PhotoImage(cert_img) 250 | show_pic['image'] = cert_photo 251 | 252 | 253 | if __name__ == "__main__": 254 | auto_working = 0 255 | login_check = 0 256 | root = tkinter.Tk() 257 | root.title("UCAS_course_grad 1.8 by wyf && YaoBIG QQ:751076061") 258 | root.geometry('620x640') 259 | root.resizable(width=False, height=False) 260 | 261 | sep_time = tkinter.Label(root, font=('Calibri', '10')) 262 | sep_time.grid(row=0, column=1, sticky=tkinter.E) 263 | 264 | thread_1 = threading.Thread(target=get_time) 265 | thread_1.setDaemon(True) 266 | thread_1.start() 267 | 268 | thread_2 = threading.Thread(target=auto_select) 269 | thread_2.setDaemon(True) 270 | thread_2.start() 271 | 272 | login_info = tkinter.Label(root, text='') 273 | login_info.grid(row=6, column=0, sticky=tkinter.W) 274 | login_info['font'] = ('Calibri', '14') 275 | 276 | select_result = tkinter.Label(root, text='') 277 | select_result.grid(row=9, sticky=tkinter.W) 278 | select_result['font'] = ('Calibri', '14') 279 | 280 | tkinter.Label(root, text='用户名(同sep)', font=('Calibri', '14')).grid(row=0, column=0, sticky=tkinter.W) 281 | user_input = tkinter.Entry(root) 282 | user_input.grid(row=1, column=0, sticky=tkinter.W) 283 | user_input['font'] = ('Calibri', '14') 284 | user_input['width'] = 30 285 | 286 | tkinter.Label(root, text='密码', font=('Calibri', '14')).grid(row=0, column=1, sticky=tkinter.W) 287 | pwd_input = tkinter.Entry(root) 288 | pwd_input['show'] = '*' 289 | pwd_input['width'] = 30 290 | pwd_input.grid(row=1, column=1, sticky=tkinter.W) 291 | pwd_input['font'] = ('Calibri', '14') 292 | pwd_input.bind('', login) 293 | 294 | get_pic = tkinter.Button(root, text='重新获取验证码') 295 | get_pic['width'] = 12 296 | get_pic.grid(row=5, column=1, sticky=tkinter.W) 297 | get_pic['font'] = ('Calibri', '14') 298 | get_pic.bind('', download_image_file) 299 | 300 | show_pic = tkinter.Label(root) 301 | show_pic.grid(row=5, column=1, sticky=tkinter.E) 302 | download_image_file(None) 303 | 304 | tkinter.Label(root, text='验证码', font=('Calibri', '14')).grid(row=2, column=0, sticky=tkinter.W) 305 | 306 | cert_code_input = tkinter.Entry(root) 307 | cert_code_input['width'] = 30 308 | cert_code_input.grid(row=5, column=0, sticky=tkinter.W) 309 | cert_code_input['font'] = ('Calibri', '14') 310 | cert_code_input.bind('', login) 311 | 312 | login_button = tkinter.Button(root, text='登 录') 313 | login_button['width'] = 6 314 | login_button['font'] = ('Calibri', '14') 315 | login_button.grid(row=6, column=1, sticky=tkinter.E) 316 | login_button.bind('', login) 317 | 318 | tkinter.Label(root, text='课程编码(一起选) 用逗号连接', font=('Calibri', '14')).grid(row=7, column=0, sticky=tkinter.W) # NOTE: 部分课程编号中有空格,请注意 319 | course_input = tkinter.Entry(root) 320 | course_input['width'] = 30 321 | course_input.grid(row=8, column=0, sticky=tkinter.W) 322 | course_input['font'] = ('Calibri', '14') 323 | course_input.bind('', select_together) 324 | 325 | tkinter.Label(root, text='课程编码(分开选) 用逗号连接', font=('Calibri', '14')).grid(row=7, column=1, sticky=tkinter.W) 326 | course_input_separate = tkinter.Entry(root) 327 | course_input_separate['width'] = 30 328 | course_input_separate.grid(row=8, column=1, sticky=tkinter.W) 329 | course_input_separate['font'] = ('Calibri', '14') 330 | course_input_separate.bind('', select_separately) 331 | 332 | course_choose = tkinter.Button(root, text='一起选') 333 | course_choose.bind('', select_together) 334 | course_choose['font'] = ('Calibri', '14') 335 | course_choose['width'] = 6 336 | course_choose.grid(row=9, column=0, sticky=tkinter.E) 337 | 338 | course_choose = tkinter.Button(root, text='分开选') 339 | course_choose.bind('', select_separately) 340 | course_choose['font'] = ('Calibri', '14') 341 | course_choose['width'] = 6 342 | course_choose.grid(row=9, column=1, sticky=tkinter.E) 343 | 344 | jianlou_switch = tkinter.Button(root, text='捡 漏') 345 | jianlou_switch.bind('', auto_switch) 346 | jianlou_switch['font'] = ('Calibri', '14') 347 | jianlou_switch['width'] = 6 348 | jianlou_switch.grid(row=9, column=1, sticky=tkinter.W) 349 | 350 | tkinter.Label(root, text='Log:', font=('Calibri', '14')).grid(row=11, column=0, sticky=tkinter.W) 351 | log = tkinter.Label(root, anchor='nw', justify='left', background='white', relief='sunken', height=21, width=50, 352 | borderwidth=2) 353 | log.grid(row=12, column=0, sticky=tkinter.W) 354 | log['font'] = ('Calibri', '9') 355 | 356 | tkinter.Label(root, text='Log_Success:', font=('Calibri', '14')).grid(row=11, column=1, sticky=tkinter.W) 357 | log_success = tkinter.Label(root, anchor='nw', justify='left', background='white', relief='sunken', height=21, 358 | width=50, borderwidth=2) 359 | log_success.grid(row=12, column=1, sticky=tkinter.W) 360 | log_success['font'] = ('Calibri', '9') 361 | 362 | root.mainloop() 363 | 364 | -------------------------------------------------------------------------------- /dist/UCAS_course.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WuYunfan/UCAS_course_script/6c570cf694501df43f30e8735e5b7c6719ae3c16/dist/UCAS_course.exe --------------------------------------------------------------------------------