RuntimeError: Input type (torch.cuda.FloatTensor) and weight type (torch.FloatTensor) should be the same
Pytorch使用过程中
torchsummary.summary( )中出现了上述错误,torchsummary是应用在pytorch中的一种结构表达方式。
# 1 if __name__ == '__main__': model = fishnet99() torchsummary.summary(model.cuda(), (3, 224, 224)) # 2 if __name__ == '__main__': model = fishnet99() torchsummary.summary(model, (3, 224, 224),device='cpu')
1 import base64 2 import binascii 3 import json 4 import os 5 import re 6 import time 7 import traceback 8 import unicodedata 9 from urllib.parse import urljoin 10 11 import requests 12 import rsa 13 from pyquery import PyQuery as pq 14 from requests import exceptions 15 16 17 def get_config(section: str, field: str): 18 filename = os.path.join(os.path.dirname(__file__), "config.json") 19 if not os.path.exists(filename): 20 raise Exception("配置文件不存在") 21 with open(filename, "r", encoding="UTF-8") as f: 22 config = json.loads(f.read()) 23 return config.get(section, {}).get(field) 24 25 26 BASE_URL = get_config("school", "base_url") 27 RASPISANIE = get_config("school", "raspisanie") 28 IGNORE_TYPE = get_config("school", "ignore_type") 29 DETAIL_CATEGORY_TYPE = get_config("school", "detail_category_type") 30 TIMEOUT = get_config("request", "timeout") 31 32 33 class Client: 34 def __init__(self, cookies={}): 35 self.key_url = urljoin(BASE_URL, "/xtgl/login_getPublicKey.html") 36 self.login_url = urljoin(BASE_URL, "/xtgl/login_slogin.html") 37 self.kaptcha_url = urljoin(BASE_URL, "/kaptcha") 38 self.headers = requests.utils.default_headers() 39 self.headers["Referer"] = self.login_url 40 self.headers[ 41 "User-Agent" 42 ] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36" 43 self.headers[ 44 "Accept" 45 ] = "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3" 46 self.sess = requests.Session() 47 self.sess.keep_alive = False 48 self.cookies = cookies 49 50 def login(self, sid, password): 51 """登录教务系统""" 52 need_verify = False 53 try: 54 # 登录页 55 req_csrf = self.sess.get( 56 self.login_url, headers=self.headers, timeout=TIMEOUT 57 ) 58 if req_csrf.status_code != 200: 59 return {"code": 2333, "msg": "教务系统挂了"} 60 # 获取csrf_token 61 doc = pq(req_csrf.text) 62 csrf_token = doc("#csrftoken").attr("value") 63 pre_cookies = self.sess.cookies.get_dict() 64 # 获取publicKey并加密密码 65 req_pubkey = self.sess.get( 66 self.key_url, headers=self.headers, timeout=TIMEOUT 67 ).json() 68 modulus = req_pubkey["modulus"] 69 exponent = req_pubkey["exponent"] 70 if str(doc("input#yzm")) == "": 71 # 不需要验证码 72 encrypt_password = self.encrypt_password(password, modulus, exponent) 73 # 登录数据 74 login_data = { 75 "csrftoken": csrf_token, 76 "yhm": sid, 77 "mm": encrypt_password, 78 } 79 # 请求登录 80 req_login = self.sess.post( 81 self.login_url, 82 headers=self.headers, 83 data=login_data, 84 timeout=TIMEOUT, 85 ) 86 doc = pq(req_login.text) 87 tips = doc("p#tips") 88 if str(tips) != "": 89 if "用户名或密码" in tips.text(): 90 return {"code": 1002, "msg": "用户名或密码不正确"} 91 else: 92 return {"code": 998, "msg": tips.text()} 93 self.cookies = self.sess.cookies.get_dict() 94 return {"code": 1000, "msg": "登录成功", "data": {"cookies": self.cookies}} 95 else: 96 # 需要验证码,返回相关页面验证信息给用户,TODO: 增加更多验证方式 97 need_verify = True 98 req_kaptcha = self.sess.get( 99 self.kaptcha_url, headers=self.headers, timeout=TIMEOUT 100 ) 101 kaptcha_pic = base64.b64encode(req_kaptcha.content).decode() 102 return { 103 "code": 1001, 104 "msg": "获取验证码成功", 105 "data": { 106 "sid": sid, 107 "csrf_token": csrf_token, 108 "cookies": pre_cookies, 109 "password": password, 110 "modulus": modulus, 111 "exponent": exponent, 112 "kaptcha_pic": kaptcha_pic, 113 "timestamp": time.time(), 114 }, 115 } 116 except exceptions.Timeout: 117 msg = "获取验证码超时" if need_verify else "登录超时" 118 return {"code": 1003, "msg": msg} 119 except ( 120 exceptions.RequestException, 121 json.decoder.JSONDecodeError, 122 AttributeError, 123 ): 124 traceback.print_exc() 125 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 126 except Exception as e: 127 traceback.print_exc() 128 msg = "获取验证码时未记录的错误" if need_verify else "登录时未记录的错误" 129 return {"code": 999, "msg": f"{msg}:{str(e)}"} 130 131 def login_with_kaptcha( 132 self, sid, csrf_token, cookies, password, modulus, exponent, kaptcha, **kwargs 133 ): 134 """需要验证码的登陆""" 135 try: 136 encrypt_password = self.encrypt_password(password, modulus, exponent) 137 login_data = { 138 "csrftoken": csrf_token, 139 "yhm": sid, 140 "mm": encrypt_password, 141 "yzm": kaptcha, 142 } 143 req_login = self.sess.post( 144 self.login_url, 145 headers=self.headers, 146 cookies=cookies, 147 data=login_data, 148 timeout=TIMEOUT, 149 ) 150 if req_login.status_code != 200: 151 return {"code": 2333, "msg": "教务系统挂了"} 152 # 请求登录 153 doc = pq(req_login.text) 154 tips = doc("p#tips") 155 if str(tips) != "": 156 if "验证码" in tips.text(): 157 return {"code": 1004, "msg": "验证码输入错误"} 158 if "用户名或密码" in tips.text(): 159 return {"code": 1002, "msg": "用户名或密码不正确"} 160 return {"code": 998, "msg": tips.text()} 161 self.cookies = self.sess.cookies.get_dict() 162 # 不同学校系统兼容差异 163 if not self.cookies.get("route"): 164 route_cookies = { 165 "JSESSIONID": self.cookies["JSESSIONID"], 166 "route": cookies["route"], 167 } 168 self.cookies = route_cookies 169 else: 170 return {"code": 1000, "msg": "登录成功", "data": {"cookies": self.cookies}} 171 except exceptions.Timeout: 172 return {"code": 1003, "msg": "登录超时"} 173 except ( 174 exceptions.RequestException, 175 json.decoder.JSONDecodeError, 176 AttributeError, 177 ): 178 traceback.print_exc() 179 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 180 except Exception as e: 181 traceback.print_exc() 182 return {"code": 999, "msg": "验证码登录时未记录的错误:" + str(e)} 183 184 def get_info(self): 185 """获取个人信息""" 186 url = urljoin(BASE_URL, "/xsxxxggl/xsxxwh_cxCkDgxsxx.html?gnmkdm=N100801") 187 try: 188 req_info = self.sess.get( 189 url, 190 headers=self.headers, 191 cookies=self.cookies, 192 timeout=TIMEOUT, 193 ) 194 if req_info.status_code != 200: 195 return {"code": 2333, "msg": "教务系统挂了"} 196 doc = pq(req_info.text) 197 if doc("h5").text() == "用户登录": 198 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 199 info = req_info.json() 200 result = { 201 "sid": info.get("xh"), 202 "name": info.get("xm"), 203 "college_name": info.get("zsjg_id", info.get("jg_id")), 204 "major_name": info.get("zszyh_id", info.get("zyh_id")), 205 "class_name": info.get("bh_id", info.get("xjztdm")), 206 "status": info.get("xjztdm"), 207 "enrollment_date": info.get("rxrq"), 208 "candidate_number": info.get("ksh"), 209 "graduation_school": info.get("byzx"), 210 "domicile": info.get("jg"), 211 "postal_code": info.get("yzbm"), 212 "politics_status": info.get("zzmmm"), 213 "nationality": info.get("mzm"), 214 "education": info.get("pyccdm"), 215 "phone_number": info.get("sjhm"), 216 "parents_number": info.get("gddh"), 217 "email": info.get("dzyx"), 218 "birth_day": info.get("csrq"), 219 "id_number": info.get("zjhm"), 220 } 221 return {"code": 1000, "msg": "获取个人信息成功", "data": result} 222 except exceptions.Timeout: 223 return {"code": 1003, "msg": "获取个人信息超时"} 224 except ( 225 exceptions.RequestException, 226 json.decoder.JSONDecodeError, 227 AttributeError, 228 ): 229 traceback.print_exc() 230 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 231 except Exception as e: 232 traceback.print_exc() 233 return {"code": 999, "msg": "获取个人信息时未记录的错误:" + str(e)} 234 235 def get_grade(self, year: int, term: int = 0, use_personal_info: bool = False): 236 """ 237 获取成绩 238 use_personal_info: 是否使用获取个人信息接口获取成绩 239 """ 240 url = urljoin( 241 BASE_URL, 242 "/cjcx/cjcx_cxDgXscj.html?doType=query&gnmkdm=N305005" 243 if use_personal_info 244 else "/cjcx/cjcx_cxXsgrcj.html?doType=query&gnmkdm=N305005", 245 ) 246 temp_term = term 247 term = term**2 * 3 248 term = "" if term == 0 else term 249 data = { 250 "xnm": str(year), # 学年数 251 "xqm": str(term), # 学期数,第一学期为3,第二学期为12, 整个学年为空'' 252 "_search": "false", 253 "nd": int(time.time() * 1000), 254 "queryModel.showCount": "100", # 每页最多条数 255 "queryModel.currentPage": "1", 256 "queryModel.sortName": "", 257 "queryModel.sortOrder": "asc", 258 "time": "0", # 查询次数 259 } 260 try: 261 req_grade = self.sess.post( 262 url, 263 headers=self.headers, 264 data=data, 265 cookies=self.cookies, 266 timeout=TIMEOUT, 267 ) 268 if req_grade.status_code != 200: 269 return {"code": 2333, "msg": "教务系统挂了"} 270 doc = pq(req_grade.text) 271 if doc("h5").text() == "用户登录": 272 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 273 grade = req_grade.json() 274 grade_items = grade.get("items") 275 if not grade_items: 276 return {"code": 1005, "msg": "获取内容为空"} 277 result = { 278 "sid": grade_items[0]["xh"], 279 "name": grade_items[0]["xm"], 280 "year": year, 281 "term": temp_term, 282 "count": len(grade_items), 283 "courses": [ 284 { 285 "course_id": i.get("kch_id"), 286 "title": i.get("kcmc"), 287 "teacher": i.get("jsxm"), 288 "class_name": i.get("jxbmc"), 289 "credit": self.align_floats(i.get("xf")), 290 "category": i.get("kclbmc"), 291 "nature": i.get("kcxzmc"), 292 "grade": self.parse_int(i.get("cj")), 293 "grade_point": self.align_floats(i.get("jd")), 294 "grade_nature": i.get("ksxz"), 295 "start_college": i.get("kkbmmc"), 296 "mark": i.get("kcbj"), 297 } 298 for i in grade_items 299 ], 300 } 301 return {"code": 1000, "msg": "获取成绩成功", "data": result} 302 except exceptions.Timeout: 303 return {"code": 1003, "msg": "获取成绩超时"} 304 except ( 305 exceptions.RequestException, 306 json.decoder.JSONDecodeError, 307 AttributeError, 308 ): 309 traceback.print_exc() 310 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 311 except Exception as e: 312 traceback.print_exc() 313 return {"code": 999, "msg": "获取成绩时未记录的错误:" + str(e)} 314 315 def get_schedule(self, year: int, term: int): 316 """获取课程表信息""" 317 url = urljoin(BASE_URL, "/kbcx/xskbcx_cxXsKb.html?gnmkdm=N2151") 318 temp_term = term 319 term = term**2 * 3 320 data = {"xnm": str(year), "xqm": str(term)} 321 try: 322 req_schedule = self.sess.post( 323 url, 324 headers=self.headers, 325 data=data, 326 cookies=self.cookies, 327 timeout=TIMEOUT, 328 ) 329 if req_schedule.status_code != 200: 330 return {"code": 2333, "msg": "教务系统挂了"} 331 doc = pq(req_schedule.text) 332 if doc("h5").text() == "用户登录": 333 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 334 schedule = req_schedule.json() 335 if not schedule.get("kbList"): 336 return {"code": 1005, "msg": "获取内容为空"} 337 result = { 338 "sid": schedule["xsxx"].get("XH"), 339 "name": schedule["xsxx"].get("XM"), 340 "year": year, 341 "term": temp_term, 342 "count": len(schedule["kbList"]), 343 "courses": [ 344 { 345 "course_id": i.get("kch_id"), 346 "title": i.get("kcmc"), 347 "teacher": i.get("xm"), 348 "class_name": i.get("jxbmc"), 349 "credit": self.align_floats(i.get("xf")), 350 "weekday": self.parse_int(i.get("xqj")), 351 "time": self.display_course_time(i.get("jc")), 352 "sessions": i.get("jc"), 353 "list_sessions": self.list_sessions(i.get("jc")), 354 "weeks": i.get("zcd"), 355 "list_weeks": self.list_weeks(i.get("zcd")), 356 "evaluation_mode": i.get("khfsmc"), 357 "campus": i.get("xqmc"), 358 "place": i.get("cdmc"), 359 "hours_composition": i.get("kcxszc"), 360 "weekly_hours": self.parse_int(i.get("zhxs")), 361 "total_hours": self.parse_int(i.get("zxs")), 362 } 363 for i in schedule["kbList"] 364 ], 365 "extra_courses": [i.get("qtkcgs") for i in schedule.get("sjkList")], 366 } 367 result = self.split_merge_display(result) 368 return {"code": 1000, "msg": "获取课表成功", "data": result} 369 except exceptions.Timeout: 370 return {"code": 1003, "msg": "获取课表超时"} 371 except ( 372 exceptions.RequestException, 373 json.decoder.JSONDecodeError, 374 AttributeError, 375 ): 376 traceback.print_exc() 377 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 378 except Exception as e: 379 traceback.print_exc() 380 return {"code": 999, "msg": "获取课表时未记录的错误:" + str(e)} 381 382 def get_academia(self): 383 """获取学业生涯情况""" 384 url_main = urljoin( 385 BASE_URL, 386 "/xsxy/xsxyqk_cxXsxyqkIndex.html?gnmkdm=N105515&layout=default", 387 ) 388 url_info = urljoin( 389 BASE_URL, "/xsxy/xsxyqk_cxJxzxjhxfyqKcxx.html?gnmkdm=N105515" 390 ) 391 try: 392 req_main = self.sess.get( 393 url_main, 394 headers=self.headers, 395 cookies=self.cookies, 396 timeout=TIMEOUT, 397 stream=True, 398 ) 399 if req_main.status_code != 200: 400 return {"code": 2333, "msg": "教务系统挂了"} 401 doc_main = pq(req_main.text) 402 if doc_main("h5").text() == "用户登录": 403 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 404 if str(doc_main("div.alert-danger")) != "": 405 return {"code": 998, "msg": doc_main("div.alert-danger").text()} 406 sid = doc_main("form#form input#xh_id").attr("value") 407 display_statistics = ( 408 doc_main("div#alertBox").text().replace(" ", "").replace("\n", "") 409 ) 410 sid = doc_main("input#xh_id").attr("value") 411 statistics = self.get_academia_statistics(display_statistics) 412 type_statistics = self.get_academia_type_statistics(req_main.text) 413 details = {} 414 for type in type_statistics.keys(): 415 details[type] = self.sess.post( 416 url_info, 417 headers=self.headers, 418 data={"xfyqjd_id": type_statistics[type]["id"]}, 419 cookies=self.cookies, 420 timeout=TIMEOUT, 421 stream=True, 422 ).json() 423 result = { 424 "sid": sid, 425 "statistics": statistics, 426 "details": [ 427 { 428 "type": type, 429 "credits": type_statistics[type]["credits"], 430 "courses": [ 431 { 432 "course_id": i.get("KCH"), 433 "title": i.get("KCMC"), 434 "situation": self.parse_int(i.get("XDZT")), 435 "display_term": self.get_display_term( 436 sid, i.get("JYXDXNM"), i.get("JYXDXQMC") 437 ), 438 "credit": self.align_floats(i.get("XF")), 439 "category": self.get_course_category(type, i), 440 "nature": i.get("KCXZMC"), 441 "max_grade": self.parse_int(i.get("MAXCJ")), 442 "grade_point": self.align_floats(i.get("JD")), 443 } 444 for i in details[type] 445 ], 446 } 447 for type in type_statistics.keys() 448 if len(details[type]) > 0 449 ], 450 } 451 return {"code": 1000, "msg": "获取学业情况成功", "data": result} 452 except exceptions.Timeout: 453 return {"code": 1003, "msg": "获取学业情况超时"} 454 except ( 455 exceptions.RequestException, 456 json.decoder.JSONDecodeError, 457 AttributeError, 458 ): 459 traceback.print_exc() 460 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 461 except Exception as e: 462 traceback.print_exc() 463 return {"code": 999, "msg": "获取学业情况时未记录的错误:" + str(e)} 464 465 def get_academia_pdf(self): 466 """获取学业生涯(学生成绩总表)pdf""" 467 url_view = urljoin(BASE_URL, "/bysxxcx/xscjzbdy_dyXscjzbView.html") 468 url_window = urljoin(BASE_URL, "/bysxxcx/xscjzbdy_dyCjdyszxView.html") 469 url_policy = urljoin(BASE_URL, "/xtgl/bysxxcx/xscjzbdy_cxXsCount.html") 470 url_filetype = urljoin(BASE_URL, "/bysxxcx/xscjzbdy_cxGswjlx.html") 471 url_common = urljoin(BASE_URL, "/common/common_cxJwxtxx.html") 472 url_file = urljoin(BASE_URL, "/bysxxcx/xscjzbdy_dyList.html") 473 url_progress = urljoin(BASE_URL, "/xtgl/progress_cxProgressStatus.html") 474 data = { 475 "gsdygx": "10628-zw-mrgs", 476 "ids": "", 477 "bdykcxzDms": "", 478 "cytjkcxzDms": "", 479 "cytjkclbDms": "", 480 "cytjkcgsDms": "", 481 "bjgbdykcxzDms": "", 482 "bjgbdyxxkcxzDms": "", 483 "djksxmDms": "", 484 "cjbzmcDms": "", 485 "cjdySzxs": "", 486 "wjlx": "pdf", 487 } 488 489 try: 490 data_view = {"time": str(round(time.time() * 1000)), "gnmkdm": "N558020"} 491 data_params = data_view 492 del data_params["time"] 493 # View接口 494 req_view = self.sess.post( 495 url_view, 496 headers=self.headers, 497 data=data_view, 498 params=data_view, 499 cookies=self.cookies, 500 timeout=TIMEOUT, 501 ) 502 if req_view.status_code != 200: 503 return {"code": 2333, "msg": "教务系统挂了"} 504 doc = pq(req_view.text) 505 if doc("h5").text() == "用户登录": 506 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 507 # Window接口 508 data_window = {"xh": ""} 509 self.sess.post( 510 url_window, 511 headers=self.headers, 512 data=data_window, 513 params=data_params, 514 cookies=self.cookies, 515 timeout=TIMEOUT, 516 ) 517 # 许可接口 518 data_policy = data 519 del data_policy["wjlx"] 520 self.sess.post( 521 url_policy, 522 headers=self.headers, 523 data=data_policy, 524 params=data_params, 525 cookies=self.cookies, 526 timeout=TIMEOUT, 527 ) 528 # 文件类型接口 529 data_filetype = data_policy 530 self.sess.post( 531 url_filetype, 532 headers=self.headers, 533 data=data_filetype, 534 params=data_params, 535 cookies=self.cookies, 536 timeout=TIMEOUT, 537 ) 538 # Common接口 539 self.sess.post( 540 url_common, 541 headers=self.headers, 542 data=data_params, 543 params=data_params, 544 cookies=self.cookies, 545 timeout=TIMEOUT, 546 ) 547 # 获取PDF文件URL 548 req_file = self.sess.post( 549 url_file, 550 headers=self.headers, 551 data=data, 552 params=data_params, 553 cookies=self.cookies, 554 timeout=TIMEOUT, 555 ) 556 doc = pq(req_file.text) 557 if "错误" in doc("title").text(): 558 error = doc("p.error_title").text() 559 return {"code": 998, "msg": error} 560 # 进度接口 561 data_progress = { 562 "key": "score_print_processed", 563 "gnmkdm": "N558020", 564 } 565 self.sess.post( 566 url_progress, 567 headers=self.headers, 568 data=data_progress, 569 params=data_progress, 570 cookies=self.cookies, 571 timeout=TIMEOUT, 572 ) 573 # 生成PDF文件URL 574 pdf = ( 575 req_file.text.replace("#成功", "") 576 .replace('"', "") 577 .replace("/", "\\") 578 .replace("\\\\", "/") 579 ) 580 # 下载PDF文件 581 req_pdf = self.sess.get( 582 urljoin(BASE_URL, pdf), 583 headers=self.headers, 584 cookies=self.cookies, 585 timeout=TIMEOUT + 2, 586 ) 587 result = req_pdf.content # 二进制内容 588 return {"code": 1000, "msg": "获取学生成绩总表pdf成功", "data": result} 589 except exceptions.Timeout: 590 return {"code": 1003, "msg": "获取成绩总表pdf超时"} 591 except ( 592 exceptions.RequestException, 593 json.decoder.JSONDecodeError, 594 AttributeError, 595 ): 596 traceback.print_exc() 597 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 598 except Exception as e: 599 traceback.print_exc() 600 return {"code": 999, "msg": "获取成绩总表pdf时未记录的错误:" + str(e)} 601 602 def get_schedule_pdf(self, year: int, term: int, name: str = "导出"): 603 """获取课表pdf""" 604 url_policy = urljoin(BASE_URL, "/kbdy/bjkbdy_cxXnxqsfkz.html") 605 url_file = urljoin(BASE_URL, "/kbcx/xskbcx_cxXsShcPdf.html") 606 origin_term = term 607 term = term**2 * 3 608 data = { 609 "xm": name, 610 "xnm": str(year), 611 "xqm": str(term), 612 "xnmc": f"{year}-{year+1}", 613 "xqmmc": str(origin_term), 614 "jgmc": "undefined", 615 "xxdm": "", 616 "xszd.sj": "true", 617 "xszd.cd": "true", 618 "xszd.js": "true", 619 "xszd.jszc": "false", 620 "xszd.jxb": "true", 621 "xszd.xkbz": "true", 622 "xszd.kcxszc": "true", 623 "xszd.zhxs": "true", 624 "xszd.zxs": "true", 625 "xszd.khfs": "true", 626 "xszd.xf": "true", 627 "xszd.skfsmc": "false", 628 "kzlx": "dy", 629 } 630 631 try: 632 # 许可接口 633 pilicy_params = {"gnmkdm": "N2151"} 634 req_policy = self.sess.post( 635 url_policy, 636 headers=self.headers, 637 data=data, 638 params=pilicy_params, 639 cookies=self.cookies, 640 timeout=TIMEOUT, 641 ) 642 if req_policy.status_code != 200: 643 return {"code": 2333, "msg": "教务系统挂了"} 644 doc = pq(req_policy.text) 645 if doc("h5").text() == "用户登录": 646 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 647 # 获取PDF文件URL 648 file_params = {"doType": "table"} 649 req_file = self.sess.post( 650 url_file, 651 headers=self.headers, 652 data=data, 653 params=file_params, 654 cookies=self.cookies, 655 timeout=TIMEOUT, 656 ) 657 doc = pq(req_file.text) 658 if "错误" in doc("title").text(): 659 error = doc("p.error_title").text() 660 return {"code": 998, "msg": error} 661 result = req_file.content # 二进制内容 662 return {"code": 1000, "msg": "获取课程表pdf成功", "data": result} 663 except exceptions.Timeout: 664 return {"code": 1003, "msg": "获取课程表pdf超时"} 665 except ( 666 exceptions.RequestException, 667 json.decoder.JSONDecodeError, 668 AttributeError, 669 ): 670 traceback.print_exc() 671 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 672 except Exception as e: 673 traceback.print_exc() 674 return {"code": 999, "msg": "获取课程表pdf时未记录的错误:" + str(e)} 675 676 def get_notifications(self): 677 """获取通知消息""" 678 url = urljoin(BASE_URL, "/xtgl/index_cxDbsy.html?doType=query") 679 data = { 680 "sfyy": "0", # 是否已阅,未阅未1,已阅为2 681 "flag": "1", 682 "_search": "false", 683 "nd": int(time.time() * 1000), 684 "queryModel.showCount": "1000", # 最多条数 685 "queryModel.currentPage": "1", # 当前页数 686 "queryModel.sortName": "cjsj", 687 "queryModel.sortOrder": "desc", # 时间倒序, asc正序 688 "time": "0", 689 } 690 try: 691 req_notification = self.sess.post( 692 url, 693 headers=self.headers, 694 data=data, 695 cookies=self.cookies, 696 timeout=TIMEOUT, 697 ) 698 if req_notification.status_code != 200: 699 return {"code": 2333, "msg": "教务系统挂了"} 700 doc = pq(req_notification.text) 701 if doc("h5").text() == "用户登录" or "错误" in doc("title").text(): 702 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 703 notifications = req_notification.json() 704 result = [ 705 {**self.split_notifications(i), "create_time": i.get("cjsj")} 706 for i in notifications.get("items") 707 ] 708 return {"code": 1000, "msg": "获取消息成功", "data": result} 709 except exceptions.Timeout: 710 return {"code": 1003, "msg": "获取消息超时"} 711 except ( 712 exceptions.RequestException, 713 json.decoder.JSONDecodeError, 714 AttributeError, 715 ): 716 traceback.print_exc() 717 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 718 except Exception as e: 719 traceback.print_exc() 720 return {"code": 999, "msg": "获取消息时未记录的错误:" + str(e)} 721 722 def get_selected_courses(self, year: int, term: int): 723 """获取已选课程信息""" 724 try: 725 url = urljoin( 726 BASE_URL, "/xsxk/zzxkyzb_cxZzxkYzbChoosedDisplay.html?gnmkdm=N253512" 727 ) 728 temp_term = term 729 term = term**2 * 3 730 data = {"xkxnm": str(year), "xkxqm": str(term)} 731 req_selected = self.sess.post( 732 url, 733 data=data, 734 headers=self.headers, 735 cookies=self.cookies, 736 timeout=TIMEOUT, 737 ) 738 if req_selected.status_code != 200: 739 return {"code": 2333, "msg": "教务系统挂了"} 740 doc = pq(req_selected.text) 741 if doc("h5").text() == "用户登录": 742 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 743 selected = req_selected.json() 744 result = { 745 "year": year, 746 "term": temp_term, 747 "count": len(selected), 748 "courses": [ 749 { 750 "course_id": i.get("kch"), 751 "class_id": i.get("jxb_id"), 752 "do_id": i.get("do_jxb_id"), 753 "title": i.get("kcmc"), 754 "teacher_id": (re.findall(r"(.*?\d+)/", i.get("jsxx")))[0], 755 "teacher": (re.findall(r"/(.*?)/", i.get("jsxx")))[0], 756 "credit": float(i.get("xf", 0)), 757 "category": i.get("kklxmc"), 758 "capacity": int(i.get("jxbrs", 0)), 759 "selected_number": int(i.get("yxzrs", 0)), 760 "place": self.get_place(i.get("jxdd")), 761 "time": self.get_course_time(i.get("sksj")), 762 "optional": int(i.get("zixf", 0)), 763 "waiting": i.get("sxbj"), 764 } 765 for i in selected 766 ], 767 } 768 return {"code": 1000, "msg": "获取已选课程成功", "data": result} 769 except exceptions.Timeout: 770 return {"code": 1003, "msg": "获取已选课程超时"} 771 except ( 772 exceptions.RequestException, 773 json.decoder.JSONDecodeError, 774 AttributeError, 775 ): 776 traceback.print_exc() 777 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 778 except Exception as e: 779 traceback.print_exc() 780 return {"code": 999, "msg": f"获取已选课程时未记录的错误:{str(e)}"} 781 782 def get_block_courses(self, year: int, term: int, block: int): 783 """获取板块课选课列表""" 784 # TODO: 优化代码 785 try: 786 # 获取head_data 787 url_head = urljoin( 788 BASE_URL, 789 "/xsxk/zzxkyzb_cxZzxkYzbIndex.html?gnmkdm=N253512&layout=default", 790 ) 791 req_head_data = self.sess.get( 792 url_head, headers=self.headers, cookies=self.cookies, timeout=TIMEOUT 793 ) 794 if req_head_data.status_code != 200: 795 return {"code": 2333, "msg": "教务系统挂了"} 796 doc = pq(req_head_data.text) 797 if doc("h5").text() == "用户登录": 798 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 799 if str(doc("div.nodata")) != "": 800 return {"code": 998, "msg": doc("div.nodata").text()} 801 got_credit_list = [i for i in doc("font[color='red']").items()] 802 if len(got_credit_list) == 0: 803 return {"code": 1005, "msg": "板块课内容为空"} 804 head_data = {"got_credit": got_credit_list[2].string} 805 806 kklxdm_list = [] 807 xkkz_id_list = [] 808 for tab_content in doc("a[role='tab']").items(): 809 onclick_content = tab_content.attr("onclick") 810 r = re.findall(r"'(.*?)'", str(onclick_content)) 811 kklxdm_list.append(r[0].strip()) 812 xkkz_id_list.append(r[1].strip()) 813 head_data["bkk1_kklxdm"] = kklxdm_list[0] 814 head_data["bkk2_kklxdm"] = kklxdm_list[1] 815 head_data["bkk3_kklxdm"] = kklxdm_list[2] 816 head_data["bkk1_xkkz_id"] = xkkz_id_list[0] 817 head_data["bkk2_xkkz_id"] = xkkz_id_list[1] 818 head_data["bkk3_xkkz_id"] = xkkz_id_list[2] 819 820 for head_data_content in doc("input[type='hidden']"): 821 name = head_data_content.attr("name") 822 value = head_data_content.attr("value") 823 head_data[str(name)] = str(value) 824 825 url_display = urljoin( 826 BASE_URL, "/xsxk/zzxkyzb_cxZzxkYzbDisplay.html?gnmkdm=N253512" 827 ) 828 display_req_data = { 829 "xkkz_id": head_data[f"bkk{block}_xkkz_id"], 830 "xszxzt": "1", 831 "kspage": "0", 832 } 833 req_display_data = self.sess.post( 834 url_display, 835 headers=self.headers, 836 data=display_req_data, 837 cookies=self.cookies, 838 timeout=TIMEOUT, 839 ) 840 doc_display = pq(req_display_data.text) 841 display_data = {} 842 for display_data_content in doc_display("input[type='hidden']").items(): 843 name = display_data_content.get("name") 844 value = display_data_content.get("value") 845 display_data[str(name)] = str(value) 846 head_data.update(display_data) 847 848 # 获取课程列表 849 url_kch = urljoin( 850 BASE_URL, "/xsxk/zzxkyzb_cxZzxkYzbPartDisplay.html?gnmkdm=N253512" 851 ) 852 url_bkk = urljoin( 853 BASE_URL, "/xsxk/zzxkyzb_cxJxbWithKchZzxkYzb.html?gnmkdm=N253512" 854 ) 855 term = term**2 * 3 856 kch_data = { 857 "bklx_id": head_data["bklx_id"], 858 "xqh_id": head_data["xqh_id"], 859 "zyfx_id": head_data["zyfx_id"], 860 "njdm_id": head_data["njdm_id"], 861 "bh_id": head_data["bh_id"], 862 "xbm": head_data["xbm"], 863 "xslbdm": head_data["xslbdm"], 864 "ccdm": head_data["ccdm"], 865 "xsbj": head_data["xsbj"], 866 "xkxnm": str(year), 867 "xkxqm": str(term), 868 "kklxdm": head_data[f"bkk{block}_kklxdm"], 869 "kkbk": head_data["kkbk"], 870 "rwlx": head_data["rwlx"], 871 "kspage": "1", 872 "jspage": "10", 873 } 874 kch_res = self.sess.post( 875 url_kch, 876 headers=self.headers, 877 data=kch_data, 878 cookies=self.cookies, 879 timeout=TIMEOUT, 880 ) 881 jkch_res = kch_res.json() 882 bkk_data = { 883 "bklx_id": head_data["bklx_id"], 884 "xkxnm": str(year), 885 "xkxqm": str(term), 886 "xkkz_id": head_data[f"bkk{block}_xkkz_id"], 887 "xqh_id": head_data["xqh_id"], 888 "zyfx_id": head_data["zyfx_id"], 889 "njdm_id": head_data["njdm_id"], 890 "bh_id": head_data["bh_id"], 891 "xbm": head_data["xbm"], 892 "xslbdm": head_data["xslbdm"], 893 "ccdm": head_data["ccdm"], 894 "xsbj": head_data["xsbj"], 895 "kklxdm": head_data[f"bkk{block}_kklxdm"], 896 "kch_id": jkch_res["tmpList"][0]["kch_id"], 897 "kkbk": head_data["kkbk"], 898 "rwlx": head_data["rwlx"], 899 "zyh_id": head_data["zyh_id"], 900 } 901 bkk_res = self.sess.post( 902 url_bkk, 903 headers=self.headers, 904 data=bkk_data, 905 cookies=self.cookies, 906 timeout=TIMEOUT, 907 ) 908 jbkk_res = bkk_res.json() 909 if block != 3 and (len(jkch_res["tmpList"]) != len(jbkk_res)): 910 return {"code": 999, "msg": "板块课编号及长度错误"} 911 temp_list = jkch_res["tmpList"] 912 block_list = jbkk_res 913 for i in range(len(temp_list)): 914 temp_list[i].update(block_list[i]) 915 916 result = { 917 "count": len(temp_list), 918 "courses": [ 919 { 920 "course_id": j["kch_id"], 921 "class_id": j.get("jxb_id"), 922 "do_id": j.get("do_jxb_id"), 923 "title": j.get("kcmc"), 924 "teacher_id": (re.findall(r"(.*?\d+)/", j.get("jsxx")))[0], 925 "teacher": (re.findall(r"/(.*?)/", j.get("jsxx")))[0], 926 "credit": float(j.get("xf"), 0), 927 "kklxdm": head_data[f"bkk{block}_kklxdm"], 928 "capacity": int(i.get("jxbrl", 0)), 929 "selected_number": int(i.get("yxzrs", 0)), 930 "place": self.get_place(i.get("jxdd")), 931 "time": self.get_course_time(i.get("sksj")), 932 } 933 for j in temp_list 934 ], 935 } 936 return {"code": 1000, "msg": "获取板块课信息成功", "data": result} 937 except exceptions.Timeout: 938 return {"code": 1003, "msg": "获取板块课信息超时"} 939 except ( 940 exceptions.RequestException, 941 json.decoder.JSONDecodeError, 942 AttributeError, 943 ): 944 traceback.print_exc() 945 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 946 except Exception as e: 947 traceback.print_exc() 948 return {"code": 999, "msg": f"获取板块课信息时未记录的错误:{str(e)}"} 949 950 def select_course( 951 self, 952 sid: str, 953 course_id: str, 954 do_id: str, 955 kklxdm: str, 956 year: int, 957 term: int, 958 ): 959 """选课""" 960 try: 961 url_select = urljoin( 962 BASE_URL, "/xsxk/zzxkyzb_xkBcZyZzxkYzb.html?gnmkdm=N253512" 963 ) 964 term = term**2 * 3 965 select_data = { 966 "jxb_ids": do_id, 967 "kch_id": course_id, 968 # 'rwlx': '3', 969 # 'rlkz': '0', 970 # 'rlzlkz': '1', 971 # 'sxbj': '1', 972 # 'xxkbj': '0', 973 # 'cxbj': '0', 974 "qz": "0", 975 # 'xkkz_id': '9B247F4EFD6291B9E055000000000001', 976 "xkxnm": str(year), 977 "xkxqm": str(term), 978 "njdm_id": str(sid[0:2]), 979 "zyh_id": str(sid[2:6]), 980 "kklxdm": str(kklxdm), 981 # 'xklc': '1', 982 } 983 req_select = self.sess.post( 984 url_select, 985 headers=self.headers, 986 data=select_data, 987 cookies=self.cookies, 988 timeout=TIMEOUT, 989 ) 990 if req_select.status_code != 200: 991 return {"code": 2333, "msg": "教务系统挂了"} 992 doc = pq(req_select.text) 993 if doc("h5").text() == "用户登录": 994 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 995 result = req_select.json() 996 return {"code": 1000, "msg": "选课成功", "data": result} 997 except exceptions.Timeout: 998 return {"code": 1003, "msg": "选课超时"} 999 except ( 1000 exceptions.RequestException, 1001 json.decoder.JSONDecodeError, 1002 AttributeError, 1003 ): 1004 traceback.print_exc() 1005 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 1006 except Exception as e: 1007 traceback.print_exc() 1008 return {"code": 999, "msg": f"选课时未记录的错误:{str(e)}"} 1009 1010 def cancel_course(self, do_id: str, course_id: str, year: int, term: int): 1011 """取消选课""" 1012 try: 1013 url_cancel = urljoin( 1014 BASE_URL, "/xsxk/zzxkyzb_tuikBcZzxkYzb.html?gnmkdm=N253512" 1015 ) 1016 term = term**2 * 3 1017 cancel_data = { 1018 "jxb_ids": do_id, 1019 "kch_id": course_id, 1020 "xkxnm": str(year), 1021 "xkxqm": str(term), 1022 } 1023 req_cancel = self.sess.post( 1024 url_cancel, 1025 headers=self.headers, 1026 data=cancel_data, 1027 cookies=self.cookies, 1028 timeout=TIMEOUT, 1029 ) 1030 if req_cancel.status_code != 200: 1031 return {"code": 2333, "msg": "教务系统挂了"} 1032 doc = pq(req_cancel.text) 1033 if doc("h5").text() == "用户登录": 1034 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 1035 result = {"status": re.findall(r"(\d+)", req_cancel.text)[0]} 1036 return {"code": 1000, "msg": "退课成功", "data": result} 1037 except exceptions.Timeout: 1038 return {"code": 1003, "msg": "选课超时"} 1039 except ( 1040 exceptions.RequestException, 1041 json.decoder.JSONDecodeError, 1042 AttributeError, 1043 ): 1044 traceback.print_exc() 1045 return {"code": 2333, "msg": "请重试,若多次失败可能是系统错误维护或需更新接口"} 1046 except Exception as e: 1047 traceback.print_exc() 1048 return {"code": 999, "msg": f"选课时未记录的错误:{str(e)}"} 1049 1050 # ============= utils ================= 1051 1052 def get_gpa(self): 1053 """获取GPA""" 1054 url = urljoin( 1055 BASE_URL, 1056 "/xsxy/xsxyqk_cxXsxyqkIndex.html?gnmkdm=N105515&layout=default", 1057 ) 1058 req_gpa = self.sess.get( 1059 url, 1060 headers=self.headers, 1061 cookies=self.cookies, 1062 timeout=TIMEOUT, 1063 ) 1064 doc = pq(req_gpa.text) 1065 if doc("h5").text() == "用户登录": 1066 return {"code": 1006, "msg": "未登录或已过期,请重新登录"} 1067 allc_str = [allc.text() for allc in doc("font[size='2px']").items()] 1068 try: 1069 gpa = float(allc_str[2]) 1070 return gpa 1071 except Exception: 1072 return "init" 1073 1074 def get_course_category(self, type, item): 1075 """根据课程号获取类别""" 1076 if type not in DETAIL_CATEGORY_TYPE: 1077 return item.get("KCLBMC") 1078 if not item.get("KCH"): 1079 return None 1080 url = urljoin(BASE_URL, f"/jxjhgl/common_cxKcJbxx.html?id={item['KCH']}") 1081 req_category = self.sess.get( 1082 url, 1083 headers=self.headers, 1084 cookies=self.cookies, 1085 timeout=TIMEOUT, 1086 ) 1087 doc = pq(req_category.text) 1088 ths = doc("th") 1089 try: 1090 data_list = [(th.text).strip() for th in ths] 1091 return data_list[6] 1092 except: 1093 return None 1094 1095 @classmethod 1096 def encrypt_password(cls, pwd, n, e): 1097 """对密码base64编码""" 1098 message = str(pwd).encode() 1099 rsa_n = binascii.b2a_hex(binascii.a2b_base64(n)) 1100 rsa_e = binascii.b2a_hex(binascii.a2b_base64(e)) 1101 key = rsa.PublicKey(int(rsa_n, 16), int(rsa_e, 16)) 1102 encropy_pwd = rsa.encrypt(message, key) 1103 result = binascii.b2a_base64(encropy_pwd) 1104 return result 1105 1106 @classmethod 1107 def parse_int(cls, digits): 1108 if not digits: 1109 return None 1110 if not digits.isdigit(): 1111 return digits 1112 return int(digits) 1113 1114 @classmethod 1115 def align_floats(cls, floats): 1116 if not floats: 1117 return None 1118 if floats == "无": 1119 return "0.0" 1120 return format(float(floats), ".1f") 1121 1122 @classmethod 1123 def display_course_time(cls, sessions): 1124 if not sessions: 1125 return None 1126 args = re.findall(r"(\d+)", sessions) 1127 start_time = RASPISANIE[int(args[0]) + 1][0] 1128 end_time = RASPISANIE[int(args[0]) + 1][1] 1129 return f"{start_time}~{end_time}" 1130 1131 @classmethod 1132 def list_sessions(cls, sessions): 1133 if not sessions: 1134 return None 1135 args = re.findall(r"(\d+)", sessions) 1136 return [n for n in range(int(args[0]), int(args[1]) + 1)] 1137 1138 @classmethod 1139 def list_weeks(cls, weeks): 1140 """返回课程所含周列表""" 1141 if not weeks: 1142 return None 1143 args = re.findall(r"[^,]+", weeks) 1144 week_list = [] 1145 for item in args: 1146 if "-" in item: 1147 weeks_pair = re.findall(r"(\d+)", item) 1148 if len(weeks_pair) != 2: 1149 continue 1150 if "单" in item: 1151 for i in range(int(weeks_pair[0]), int(weeks_pair[1]) + 1): 1152 if i % 2 == 1: 1153 week_list.append(i) 1154 elif "双" in item: 1155 for i in range(int(weeks_pair[0]), int(weeks_pair[1]) + 1): 1156 if i % 2 == 0: 1157 week_list.append(i) 1158 else: 1159 for i in range(int(weeks_pair[0]), int(weeks_pair[1]) + 1): 1160 week_list.append(i) 1161 else: 1162 week_num = re.findall(r"(\d+)", item) 1163 if len(week_num) == 1: 1164 week_list.append(int(week_num[0])) 1165 return week_list 1166 1167 @classmethod 1168 def get_academia_statistics(cls, display_statistics): 1169 display_statistics = "".join(display_statistics.split()) 1170 gpa_list = re.findall(r"([0-9]{1,}[.][0-9]*)", display_statistics) 1171 if len(gpa_list) == 0 or not cls.is_number(gpa_list[0]): 1172 gpa = None 1173 else: 1174 gpa = float(gpa_list[0]) 1175 plan_list = re.findall( 1176 r"计划总课程(\d+)门通过(\d+)门?.*未通过(\d+)门?.*未修(\d+)?.*在读(\d+)门?.*计划外?.*通过(\d+)门?.*未通过(\d+)门", 1177 display_statistics, 1178 ) 1179 if len(plan_list) == 0 or len(plan_list[0]) < 7: 1180 return {"gpa": gpa} 1181 plan_list = plan_list[0] 1182 return { 1183 "gpa": gpa, # 平均学分绩点GPA 1184 "planed_courses": { 1185 "total": int(plan_list[0]), # 计划内总课程数 1186 "passed": int(plan_list[1]), # 计划内已过课程数 1187 "failed": int(plan_list[2]), # 计划内未过课程数 1188 "missed": int(plan_list[3]), # 计划内未修课程数 1189 "in": int(plan_list[4]), # 计划内在读课程数 1190 }, 1191 "unplaned_courses": { 1192 "passed": int(plan_list[5]), # 计划外已过课程数 1193 "failed": int(plan_list[6]), # 计划外未过课程数 1194 }, 1195 } 1196 1197 @classmethod 1198 def get_academia_type_statistics(cls, content: str): 1199 finder = re.findall( 1200 r"\"(.*) .*要求学分.*:([0-9]{1,}[.][0-9]*|0| ).*获得学分.*:([0-9]{1,}[.][0-9]*|0| ).*未获得学分.*:([0-9]{1,}[.][0-9]*|0| )[\s\S]*?<span id='showKc(.*)'></span>", 1201 content, 1202 ) 1203 finder_list = list({}.fromkeys(finder).keys()) 1204 academia_list = [ 1205 list(i) 1206 for i in finder_list 1207 if i[0] != "" # 类型名称不为空 1208 and len(i[0]) <= 20 # 避免正则到首部过长类型名称 1209 and "span" not in i[-1] # 避免正则到尾部过长类型名称 1210 and i[0] not in IGNORE_TYPE # 忽略的类型名称 1211 ] 1212 result = { 1213 i[0]: { 1214 "id": i[-1], 1215 "credits": { 1216 "required": i[1] if cls.is_number(i[1]) and i[1] != "0" else None, 1217 "earned": i[2] if cls.is_number(i[2]) and i[2] != "0" else None, 1218 "missed": i[3] if cls.is_number(i[3]) and i[3] != "0" else None, 1219 }, 1220 } 1221 for i in academia_list 1222 } 1223 return result 1224 1225 @classmethod 1226 def get_display_term(cls, sid, year, term): 1227 """ 1228 计算培养方案具体学期转化成中文 1229 note: 留级和当兵等情况会不准确 1230 """ 1231 if (sid and year and term) is None: 1232 return None 1233 grade = int(sid[0:2]) 1234 year = int(year[2:4]) 1235 term = int(term) 1236 dict = { 1237 grade: "大一上" if term == 1 else "大一下", 1238 grade + 1: "大二上" if term == 1 else "大二下", 1239 grade + 2: "大三上" if term == 1 else "大三下", 1240 grade + 3: "大四上" if term == 1 else "大四下", 1241 } 1242 return dict.get(year) 1243 1244 @classmethod 1245 def split_merge_display(cls, schedule): 1246 """ 1247 拆分同周同天同课程不同时段数据合并的问题 1248 """ 1249 repetIndex = [] 1250 count = 0 1251 for items in schedule["courses"]: 1252 for index in range(len(schedule["courses"])): 1253 if (schedule["courses"]).index(items) == count: # 如果对比到自己就忽略 1254 continue 1255 elif ( 1256 items["course_id"] 1257 == schedule["courses"][index]["course_id"] # 同周同天同课程 1258 and items["weekday"] == schedule["courses"][index]["weekday"] 1259 and items["weeks"] == schedule["courses"][index]["weeks"] 1260 ): 1261 repetIndex.append(index) # 满足条件记录索引 1262 count += 1 # 记录当前对比课程的索引 1263 if len(repetIndex) % 2 != 0: # 暂时考虑一天两个时段上同一门课,不满足条件不进行修改 1264 return schedule 1265 for r in range(0, len(repetIndex), 2): # 索引数组两两成对,故步进2循环 1266 fir = repetIndex[r] 1267 sec = repetIndex[r + 1] 1268 if len(re.findall(r"(\d+)", schedule["courses"][fir]["sessions"])) == 4: 1269 schedule["courses"][fir]["sessions"] = ( 1270 re.findall(r"(\d+)", schedule["courses"][fir]["sessions"])[0] 1271 + "-" 1272 + re.findall(r"(\d+)", schedule["courses"][fir]["sessions"])[1] 1273 + "节" 1274 ) 1275 schedule["courses"][fir]["list_sessions"] = cls.list_sessions( 1276 schedule["courses"][fir]["sessions"] 1277 ) 1278 schedule["courses"][fir]["time"] = cls.display_course_time( 1279 schedule["courses"][fir]["sessions"] 1280 ) 1281 1282 schedule["courses"][sec]["sessions"] = ( 1283 re.findall(r"(\d+)", schedule["courses"][sec]["sessions"])[2] 1284 + "-" 1285 + re.findall(r"(\d+)", schedule["courses"][sec]["sessions"])[3] 1286 + "节" 1287 ) 1288 schedule["courses"][sec]["list_sessions"] = cls.list_sessions( 1289 schedule["courses"][sec]["sessions"] 1290 ) 1291 schedule["courses"][sec]["time"] = cls.display_course_time( 1292 schedule["courses"][sec]["sessions"] 1293 ) 1294 return schedule 1295 1296 @classmethod 1297 def split_notifications(cls, item): 1298 if not item.get("xxnr"): 1299 return {"type": None, "content": None} 1300 content_list = re.findall(r"(.*):(.*)", item["xxnr"]) 1301 if len(content_list) == 0: 1302 return {"type": None, "content": item["xxnr"]} 1303 return {"type": content_list[0][0], "content": content_list[0][1]} 1304 1305 @classmethod 1306 def get_place(cls, place): 1307 return place.split("<br/>")[0] if "<br/>" in place else place 1308 1309 @classmethod 1310 def get_course_time(cls, time): 1311 return "、".join(time.split("<br/>")) if "<br/>" in time else time 1312 1313 @classmethod 1314 def is_number(cls, s): 1315 if s == "": 1316 return False 1317 try: 1318 float(s) 1319 return True 1320 except ValueError: 1321 pass 1322 try: 1323 for i in s: 1324 unicodedata.numeric(i) 1325 return True 1326 except (TypeError, ValueError): 1327 pass 1328 return False