├── README.md ├── icourses.py ├── old ├── Fuck.py └── fucklesson_vpn.py └── requirement.txt /README.md: -------------------------------------------------------------------------------- 1 | # icourse 2 | 3 | ### 如何下载: 4 | 5 | 1. 执行下面的命令 6 | 7 | ```bash 8 | git clone https://github.com/H4ckF0rFun/Fuck-Lesson.git 9 | ``` 10 | 11 | 2. 安装python3 依赖库 12 | 13 | ```bash 14 | python3 -m pip install -r requirement.txt -i https://pypi.tuna.tsinghua.edu.cn/simple 15 | ``` 16 | 17 | ### 食用方法: 18 | 19 | 1. 先在网站上把要选的课加进收藏列表 20 | 2. 执行下面的命令 21 | 22 | ```bash 23 | python3 ./icourse.py username password batch_id [ loop (optional)] 24 | ``` 25 | 26 | ### 参数说明: 27 | 28 | 1. username : 你的账号 29 | 2. password : 你的密码 30 | 3. batch_id : 选课批次, 就是在网站刚登录进去的时候弹出的那个选课批次,一般情况下写0就行(0为第1个选课批次,1为第2个,以此类推···) 31 | 4. loop: 指的是如果都抢到了的话,就重新登录继续再抢,一直循环 (正常情况下是 直接退出了。主要是为了防止服务器重新刷新数据,导致已经选择的课都没了) 32 | 33 | ### 具体的例子: 34 | 35 | ```bash 36 | python3 ./icourse.py 21210000 aaaaaaaa 0 37 | ``` 38 | 39 | --- 40 | 如果你觉得有用,请给我一个小小的star ❤❤❤ 41 | -------------------------------------------------------------------------------- /icourses.py: -------------------------------------------------------------------------------- 1 | from copy import deepcopy 2 | from Cryptodome.Cipher import AES 3 | 4 | import time 5 | import ddddocr 6 | import threading 7 | import requests 8 | import base64 9 | import json 10 | import sys 11 | import urllib3 12 | 13 | from urllib3.exceptions import InsecureRequestWarning 14 | 15 | 16 | 17 | if len(sys.argv) < 4: 18 | print('Usage: %s username password batchId ' % sys.argv[0]) 19 | exit(-1) 20 | 21 | DEBUG_REQUEST_COUNT = 0 22 | urllib3.disable_warnings(InsecureRequestWarning) 23 | 24 | WorkThreadCount = 8 25 | ocr = ddddocr.DdddOcr() 26 | 27 | def pkcs7padding(data, block_size=16): 28 | if type(data) != bytearray and type(data) != bytes: 29 | raise TypeError("仅支持 bytearray/bytes 类型!") 30 | pl = block_size - (len(data) % block_size) 31 | return data + bytearray([pl for i in range(pl)]) 32 | 33 | class iCourses: 34 | mutex = threading.Lock() 35 | 36 | def __init__(self): 37 | self.aeskey = '' 38 | self.loginname='' 39 | self.password = '' 40 | self.captcha = '' 41 | self.uuid = '' 42 | self.token = '' 43 | self.batchId = '' 44 | self.s = requests.session() 45 | 46 | self.is_login = False 47 | self.favorite = None 48 | self.select = None 49 | self.batchlist = None 50 | 51 | self.current = None 52 | self.error_code = 0 53 | self.try_if_capacity_full = True 54 | 55 | def login(self,username,password): 56 | index ='https://icourses.jlu.edu.cn/' 57 | 58 | headers = { 59 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 60 | 'Host': 'icourses.jlu.edu.cn', 61 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 62 | } 63 | #get aes key 64 | html = self.s.get(url=index,headers=headers,verify=False).text 65 | start = html.find('"',html.find('loginVue.loginForm.aesKey')) + 1 66 | end = html.find('"',start) 67 | 68 | self.aeskey = html[start:end].encode('utf-8') 69 | self.loginname = username 70 | self.password = base64.b64encode(AES.new(self.aeskey,AES.MODE_ECB).encrypt(pkcs7padding(password.encode('utf-8')))) 71 | # 72 | get_url = 'https://icourses.jlu.edu.cn/xsxk/auth/captcha' 73 | 74 | headers={ 75 | 'Host': 'icourses.jlu.edu.cn', 76 | 'Origin': 'https://icourses.jlu.edu.cn', 77 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/profile/index.html', 78 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 79 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 80 | } 81 | try: 82 | data = json.loads(self.s.post(url=get_url,headers=headers,verify=False).text) 83 | except: 84 | print("get captcha failed!") 85 | exit(0) 86 | # 87 | self.uuid = data['data']['uuid'] 88 | captcha = data['data']['captcha'] 89 | self.captcha = ocr.classification(base64.b64decode(captcha[captcha.find(',') + 1:])) 90 | login_url = 'https://icourses.jlu.edu.cn/xsxk/auth/login' 91 | 92 | payload = { 93 | 'loginname' : self.loginname, 94 | 'password' : self.password.decode('utf-8'), 95 | 'captcha' : self.captcha, 96 | 'uuid' : self.uuid 97 | } 98 | 99 | response = json.loads(self.s.post(url=login_url,headers=headers,data = payload,verify=False).text) 100 | if response['code'] == 200 and response['msg'] == '登录成功': 101 | self.token = response['data']['token'] 102 | s = '' 103 | s += 'login success!\n' 104 | s += '=' * 0x40 + '\n' 105 | s += '\t\t@XH: %s'%response['data']['student']['XH']+ '\n' 106 | s += '\t\t@XM: %s'%response['data']['student']['XM']+ '\n' 107 | s += '\t\t@ZYMC: %s'%response['data']['student']['ZYMC']+ '\n' 108 | s += '=' * 0x40+ '\n' 109 | for c in response['data']['student']['electiveBatchList']: 110 | s += '\t\t@name: %s'%c['name']+ '\n' 111 | s += '\t\t@BeginTime: %s'%c['beginTime']+ '\n' 112 | s += '\t\t@EndTime: %s'%c['endTime']+ '\n' 113 | s += '=' * 0x40+ '\n' 114 | print(s) 115 | self.batchlist = response['data']['student']['electiveBatchList'] 116 | self.is_login = True 117 | return True 118 | else: 119 | print('login failed! ') 120 | print('reason: %s'%response['msg']) 121 | return False 122 | 123 | # self.s sda 124 | def setbatchId(self,idx): 125 | url = 'https://icourses.jlu.edu.cn/xsxk/elective/user' 126 | 127 | headers = { 128 | 'Host': 'icourses.jlu.edu.cn', 129 | 'Origin': 'https://icourses.jlu.edu.cn', 130 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/profile/index.html', 131 | 'Authorization':self.token , 132 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 133 | } 134 | 135 | try: 136 | self.batchId = self.batchlist[idx]['code'] 137 | except: 138 | print('No such batch Id') 139 | return 140 | 141 | payload = { 142 | 'batchId':self.batchId 143 | } 144 | d = json.loads(self.s.post(url=url,headers=headers,data=payload,verify=False).text) 145 | if 200 != d['code']: 146 | print("set batchid failed") 147 | return 148 | c = self.batchlist[idx] 149 | print('Selected BatchId:') 150 | s = '' 151 | s += '=' * 0x40+ '\n' 152 | s += '\t\t@name: %s'%c['name']+ '\n' 153 | s += '\t\t@BeginTime: %s'%c['beginTime']+ '\n' 154 | s += '\t\t@EndTime: %s'%c['endTime']+ '\n' 155 | s += '=' * 0x40 + '\n' 156 | print(s) 157 | 158 | url = 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchId 159 | 160 | headers = { 161 | 'Host': 'icourses.jlu.edu.cn', 162 | 'Origin': 'https://icourses.jlu.edu.cn', 163 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/profile/index.html', 164 | 'Authorization':self.token , 165 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 166 | } 167 | #为什么这里必须要请求一次连接 168 | self.s.get(url=url,headers=headers,verify=False) 169 | 170 | def del_lesson(self,ClassType,ClassId,SecretVal): 171 | post_url = 'https://icourses.jlu.edu.cn/xsxk/elective/clazz/del' 172 | 173 | headers = { 174 | 'Host': 'icourses.jlu.edu.cn', 175 | 'Origin': 'https://icourses.jlu.edu.cn', 176 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchid, 177 | 'Authorization':self.token , 178 | 'batchId': self.batchId, 179 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 180 | } 181 | 182 | payload = { 183 | 'clazzType':ClassType, 184 | 'clazzId' : ClassId, 185 | 'secretVal' : SecretVal, 186 | 'source':'yxkcyx' 187 | } 188 | response = json.loads(self.s.post(url=post_url,headers=headers,data=payload,verify=False).text) 189 | 190 | if response['code'] == 200: 191 | print('del success!') 192 | else: 193 | print('del failed: %s'%response['msg']) 194 | 195 | #已选课程 196 | def get_select(self): 197 | post_url = 'https://icourses.jlu.edu.cn/xsxk/elective/select' 198 | 199 | headers = { 200 | 'Host': 'icourses.jlu.edu.cn', 201 | 'Origin': 'https://icourses.jlu.edu.cn', 202 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchId, 203 | 'Authorization':self.token , 204 | 'batchId': self.batchId, 205 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 206 | } 207 | 208 | response = json.loads(self.s.post(url=post_url,headers=headers,verify=False).text) 209 | if response['code'] == 200: 210 | self.select = response['data'] 211 | else: 212 | print('get_select failed :%s'%response['msg']) 213 | pass 214 | 215 | #获取收藏课程列表. 216 | def get_favorite(self): 217 | post_url = 'https://icourses.jlu.edu.cn/xsxk/sc/clazz/list' 218 | 219 | headers = { 220 | 'Host': 'icourses.jlu.edu.cn', 221 | 'Origin': 'https://icourses.jlu.edu.cn', 222 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchId, 223 | 'Authorization':self.token , 224 | 'batchId': self.batchId, 225 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 226 | } 227 | cookies = { 228 | 'Authorization':self.token 229 | } 230 | t = self.s.post(url = post_url,headers=headers,cookies=cookies,verify=False) 231 | response = json.loads(t.text) 232 | if response['code'] == 200: 233 | self.favorite = response['data'] 234 | else: 235 | print('get_favorite failed :%s'%response['msg']) 236 | 237 | 238 | # 选择一个课的接口... 239 | def select_favorite(self,ClassType,ClassId,SecretVal): 240 | #在收藏页面添加的接口和在主修课程页面添加的接口不一样。 241 | post_url = 'https://icourses.jlu.edu.cn/xsxk/sc/clazz/addxk' 242 | 243 | headers = { 244 | 'Host': 'icourses.jlu.edu.cn', 245 | 'Origin': 'https://icourses.jlu.edu.cn', 246 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchId, 247 | 'Authorization':self.token , 248 | 'batchId': self.batchId, 249 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 250 | } 251 | 252 | payload = { 253 | 'clazzType':ClassType, 254 | 'clazzId':ClassId, 255 | 'secretVal' : SecretVal 256 | } 257 | 258 | response = json.loads(self.s.post(url=post_url,headers=headers,data=payload,verify=False).text) 259 | 260 | return response 261 | 262 | def find(self,key): 263 | post_url = 'https://icourses.jlu.edu.cn/xsxk/elective/clazz/list' 264 | 265 | headers = { 266 | 'Host': 'icourses.jlu.edu.cn', 267 | 'Origin': 'https://icourses.jlu.edu.cn', 268 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchId, 269 | 'Authorization':self.token , 270 | 'batchId': self.batchId, 271 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 272 | } 273 | 274 | payload = { 275 | "campus": "01", # 校区. 276 | "teachingClassType":"TJKC", # FANKC 或者是 TJKC 277 | "pageNumber":1, 278 | "pageSize":999999, #列出所有. 279 | "orderBy":"", 280 | 'KEY':key 281 | } 282 | 283 | response = json.loads(self.s.post(url=post_url,headers=headers,json=payload,verify=False).text) 284 | 285 | ''' 286 | 课程信息: 287 | 每一个老师的教学班 288 | ''' 289 | 290 | if response['code'] == 200: 291 | for item in response['data']['rows']: 292 | print("%-20s %-10s %-10s %-20s"%( 293 | item['KCM'],item['KCLB'],item['KCXZ'],item['KKDW'] 294 | )) 295 | 296 | for tech in item["tcList"]: 297 | print(' ' * 8 + '%-20s %-10s %-20d %-20s '%( 298 | tech['JXBID'],tech['SKJS'],tech['classCapacity'],tech['TJBJ'] 299 | )) 300 | 301 | print('') 302 | else: 303 | print('get all lesson failed: %s'%response['msg']) 304 | 305 | 306 | #添加到收藏课程列表.clazzID如何确定 307 | def add_to_favorite(self,clazzType,clazzId,SecretVal): 308 | post_url = 'https://icourses.jlu.edu.cn/xsxk/sc/clazz/add' 309 | 310 | headers = { 311 | 'Host': 'icourses.jlu.edu.cn', 312 | 'Origin': 'https://icourses.jlu.edu.cn', 313 | 'Referer': 'https://icourses.jlu.edu.cn/xsxk/elective/grablessons?batchId=' + self.batchid, 314 | 'Authorization':self.token , 315 | 'batchId': self.batchId, 316 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62', 317 | } 318 | 319 | payload = { 320 | "clazzType":clazzType, #貌似只能从主修课程里面选择?,查看全校课程里面没有选课按钮.... 321 | "clazzId":clazzId, # 322 | "secretVal":SecretVal, 323 | } 324 | 325 | return json.loads(self.s.post(url=post_url,headers=headers,data=payload,verify=False).text) 326 | 327 | def PrintSelect(self): 328 | print("="*20 + 'My Select' + '='*20) 329 | if self.select != None: 330 | for item in self.select: 331 | print('Teacther: %-10sName: %-20s Id: %-30s'%(item['SKJS'],item['KCM'],item['JXBID'])) 332 | 333 | def PrintFavorite(self): 334 | print("="*20 + 'Favorite' + '='*20) 335 | if self.favorite != None: 336 | for item in self.favorite: 337 | print('Teacther: %-10sName: %-20s Id: %-30sclazzType: %-10s'%(item['SKJS'],item['KCM'],item['JXBID'],item['teachingClassType'])) 338 | 339 | print('=' * 48) 340 | 341 | 342 | #普通的选课(对收藏中的所有课都选择,) 343 | def SelectMyFavorite(self): 344 | if self.favorite != None: 345 | for item in self.favorite: 346 | self.select_favorite(item['teachingClassType'],item['JXBID'],item['secretVal']) 347 | 348 | 349 | def workThread(self,clazzType,clazzId,SecretVal,Name): 350 | tmp = deepcopy(self) 351 | 352 | global DEBUG_REQUEST_COUNT 353 | 354 | while True: 355 | try: 356 | response = tmp.select_favorite(clazzType,clazzId,SecretVal) 357 | except : 358 | break 359 | 360 | code = response['code'] 361 | msg = response['msg'] 362 | 363 | self.mutex.acquire() 364 | 365 | DEBUG_REQUEST_COUNT += 1 366 | 367 | if self.current.get(clazzId) != None: 368 | #正在抢课。 369 | if self.current[clazzId] == 'doing': 370 | if code == 200: 371 | print('select [%s] success'%Name) 372 | self.current[clazzId] = 'done' 373 | self.mutex.release() 374 | break # 375 | 376 | elif code == 500 : 377 | if msg == '该课程已在选课结果中': 378 | print('[%s] %s'%(Name,msg)) 379 | self.current[clazzId] = 'done' 380 | self.mutex.release() 381 | break 382 | 383 | #时间未开始继续尝试. 384 | if msg == '本轮次选课暂未开始': 385 | print('[%s]本轮次选课暂未开始'%(Name)) 386 | self.mutex.release() 387 | continue 388 | # 389 | if msg == '课容量已满': 390 | print(Name + "课容量已满") 391 | self.mutex.release() 392 | if self.try_if_capacity_full: 393 | continue 394 | else: 395 | break 396 | print('[%s] %s'%(Name,msg)) #错误信息,继续尝试... 397 | self.mutex.release() 398 | break 399 | elif code == 401: #被顶下去了,重新登录 400 | print(msg) 401 | self.error_code = 401 402 | self.mutex.release() 403 | break 404 | else: 405 | print('[%d]: failed,try again'%code) 406 | self.mutex.release() 407 | continue 408 | else: 409 | self.mutex.release() 410 | break 411 | else: 412 | self.mutex.release() 413 | break 414 | 415 | 416 | def FuckMyFavorite(self): 417 | self.get_favorite() 418 | 419 | thread = {} 420 | if None != self.favorite: 421 | self.current = {} 422 | 423 | for item in self.favorite: 424 | key = item['JXBID'] 425 | thread[key] = [] 426 | 427 | self.mutex.acquire() 428 | self.current[key] = 'doing' 429 | self.mutex.release() 430 | 431 | args = (item['teachingClassType'],item['JXBID'],item['secretVal'],item['KCM']) 432 | 433 | for i in range(WorkThreadCount): 434 | thread[key].append(threading.Thread(target=self.workThread,args=args)) 435 | thread[key][-1].start() 436 | 437 | #wait all thread exit 438 | 439 | for key in thread: 440 | for t in thread[key]: 441 | t.join() 442 | 443 | print('end...') 444 | pass 445 | ''' 446 | TJKC 推介课程 447 | FANKC 主修课程 448 | ''' 449 | if __name__ == '__main__': 450 | while True: 451 | failed_count = 999999999999 452 | a = iCourses() 453 | 454 | #尝试登录... 455 | for i in range(failed_count): 456 | if a.login(sys.argv[1],sys.argv[2]): 457 | break 458 | time.sleep(0.02) 459 | if a.is_login == False: 460 | print('登录失败') 461 | exit(0) 462 | 463 | a.setbatchId(int(sys.argv[3])) 464 | a.get_favorite() 465 | # 466 | a.PrintFavorite() 467 | a.FuckMyFavorite() 468 | 469 | if a.error_code != 0: 470 | print('error: ' + str(a.error_code)) 471 | continue 472 | 473 | #获取已选的课 474 | a.get_select() 475 | a.PrintSelect() 476 | print('DEBUG_REQUEST_COUNT:%d \n' % DEBUG_REQUEST_COUNT) 477 | 478 | if len(sys.argv) == 4: 479 | break 480 | time.sleep(0.02) 481 | 482 | -------------------------------------------------------------------------------- /old/Fuck.py: -------------------------------------------------------------------------------- 1 | # -*- coding: UTF-8 -*- 2 | import random 3 | import requests 4 | import json 5 | import thread 6 | import threading 7 | import re 8 | import time 9 | import os 10 | import hashlib 11 | import getpass 12 | from requests import sessions 13 | 14 | login_success_headers = { 15 | 'Host': 'uims.jlu.edu.cn', 16 | 'Origin': 'https://uims.jlu.edu.cn', 17 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62', 18 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 19 | 'Referer': 'https://uims.jlu.edu.cn/ntms/index.do', 20 | } 21 | 22 | stuId = "" 23 | splanId = 0 24 | termId = 0 25 | 26 | #登录,成功后返回一个session 27 | #md5("UIMS" + username + password) 28 | 29 | def login(username="",password=""): 30 | session = requests.Session() 31 | 32 | verification_code = 'https://uims.jlu.edu.cn/ntms/open/get-captcha-image.do?s='+str(random.random()) 33 | login_auth = "https://uims.jlu.edu.cn/ntms/j_spring_security_check" 34 | #下载验证码 35 | headers = { 36 | 'Host': 'uims.jlu.edu.cn', 37 | "Referer": "https://uims.jlu.edu.cn/ntms/", 38 | "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62", 39 | "Origin": "https://uims.jlu.edu.cn" 40 | } 41 | print("[*]downloading the verification code...") 42 | verification_code_res = session.get(url = verification_code,headers=headers) 43 | with open("./vcode.png","wb") as file: 44 | file.write(verification_code_res.content) 45 | 46 | os.startfile("vcode.png") 47 | #让用户自己输入验证码 48 | print "[#]please input vcode >", 49 | vcode = str(raw_input()) 50 | #登录 51 | print("[*]login....") 52 | #表单方式提交,不是json 53 | payload = { 54 | "username":username, 55 | "password":password, 56 | "mousePath":"", 57 | "vcode": vcode 58 | } 59 | cookies = { 60 | "loginPage":"userLogin.jsp", 61 | "alu":username, 62 | "pwdStrength":"3" 63 | } 64 | headers={ 65 | 'Host': 'uims.jlu.edu.cn', 66 | 'Origin': 'https://uims.jlu.edu.cn', 67 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62', 68 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 69 | 'Referer': 'https://uims.jlu.edu.cn/ntms/userLogin.jsp', 70 | } 71 | response = session.post(data=payload,url = login_auth,headers=headers,cookies=cookies) 72 | print("[#]statu code %d"%response.status_code) 73 | #登录成功会重定向到index.do 74 | if response.url == "https://uims.jlu.edu.cn/ntms/index.do": 75 | print("[#]login success!") 76 | return session 77 | else: 78 | print("[x]login error!") 79 | session.close() 80 | return None 81 | 82 | #获取个人信息 83 | def GetMyInfo(session): 84 | url = "https://uims.jlu.edu.cn/ntms/service/res.do" 85 | payload={ 86 | "tag":"studInfoAll@student", 87 | "branch":"self", 88 | "params":{} 89 | } 90 | response = session.post(url=url,json=payload,headers=login_success_headers) 91 | return json.loads(response.text) 92 | #打印全部课程(供选择的课) 93 | def PrintAllLessons(session): 94 | url = "https://uims.jlu.edu.cn/ntms/service/res.do" 95 | payload={ 96 | "type":"search", 97 | "tag":"apl@gxSelect", 98 | "branch":"default", 99 | "params":{ 100 | #"mooc":"Y", #慕课在线课程 101 | "campus":"1401", #应该是校区,1401貌似是前卫南区 102 | "splanId":splanId, #这里可能需要修改 103 | "termId":termId #这里可能需要修改 104 | }, 105 | "orderBy":"lesson.courseInfo.courName" 106 | } 107 | 108 | response = session.post(url=url,json=payload,headers=login_success_headers) 109 | LessonList = json.loads(response.text)["value"] 110 | 111 | print ("%-11s %-45s %-45s"%("aplId","CourseName","SchoolName")) 112 | for item in LessonList: 113 | aplId = item["aplId"] 114 | name = item['lesson']['courseInfo']['courName'] 115 | school = item['lesson']['teachSchool']['schoolName'] 116 | print ("%-11d %-45s %-45s"%(aplId,name.encode("gbk"),school.encode("gbk"))) 117 | 118 | #输出选课列表(包含未选课程) 119 | def PrintMySelList(session): 120 | url = 'https://uims.jlu.edu.cn/ntms/service/res.do' 121 | payload = { 122 | "tag":"lessonSelectLog@selectStore", 123 | "branch":"default", 124 | "params":{ 125 | "splanId":splanId 126 | } 127 | } 128 | response = session.post(url=url,json=payload,headers=login_success_headers) 129 | LessonList = json.loads(response.text)["value"] 130 | 131 | print ("%-11s%-45s%-45s%-45s"%("lslId","CourseName","SchoolName","Y/N")) 132 | for item in LessonList: 133 | lslId = item["lslId"] 134 | name = item['lesson']['courseInfo']['courName'] 135 | school = item['lesson']['teachSchool']['schoolName'] 136 | selected = item["selectResult"] 137 | print ("%-11d%-45s%-45s%-45s"%(lslId,name.encode("gbk"),school.encode("gbk"),selected.encode("gbk"))) 138 | 139 | #输出已选课程列表 140 | def PrintMySelectedList(session): 141 | url = 'https://uims.jlu.edu.cn/ntms/service/res.do' 142 | payload = { 143 | "tag":"teachClassStud@schedule", 144 | "branch":"self", 145 | "params":{ 146 | "termId":termId 147 | } 148 | } 149 | response = session.post(url=url,json=payload,headers=login_success_headers) 150 | LessonList = json.loads(response.text)["value"] 151 | for item in LessonList: 152 | name = item["teachClassMaster"]["lessonSegment"]["fullName"] 153 | print("%s "%name.encode("gbk")) 154 | for teacher in item["teachClassMaster"]["lessonTeachers"]: 155 | print("\t\t%s"%teacher["teacher"]["name"].encode("gbk")) 156 | 157 | #获取选课信息 158 | def GetSelLesInfo(session): 159 | url ="https://uims.jlu.edu.cn/ntms/service/res.do" 160 | payload = { 161 | "tag":"common@selectPlan", 162 | "branch":"byStudentSet", 163 | "params":{ 164 | "studId":stuId 165 | } 166 | } 167 | response = session.post(url=url,json=payload,headers=login_success_headers) 168 | return json.loads(response.text) 169 | 170 | #输出选课日志的锁 171 | SelectLogLock = threading.Lock() 172 | #选课 173 | def SelectIt(session,lsltId): 174 | url = 'https://uims.jlu.edu.cn/ntms/action/select/select-lesson.do' 175 | payload = { 176 | "lsltId":lsltId, 177 | "opType":"Y" 178 | } 179 | #加个超时,要不然卡住了 180 | response = session.post(url=url,json=payload,headers=login_success_headers,timeout=1) 181 | result = json.loads(response.text) 182 | #输出加个锁,要不然窜行了 183 | 184 | SelectLogLock.acquire() 185 | print("errno: %d msg:%s"%(result["errno"],result["msg"].encode("gbk"))) 186 | SelectLogLock.release() 187 | return result["errno"] 188 | 189 | #退课 190 | def CancelIt(session,lsltId): 191 | url = 'https://uims.jlu.edu.cn/ntms/action/select/select-lesson.do' 192 | payload = { 193 | "lsltId":lsltId, 194 | "opType":"N" 195 | } 196 | response = session.post(url=url,json=payload,headers=login_success_headers) 197 | result = json.loads(response.text) 198 | print("errno: %d msg:%s"%(result["errno"],result["msg"].encode("gbk"))) 199 | return result["errno"] 200 | 201 | #获取课程的详细信息:有哪些老师授课, 202 | def GetLesDetailedInfo(session,lslId): 203 | url = 'https://uims.jlu.edu.cn/ntms/service/res.do' 204 | payload = { 205 | "tag":"lessonSelectLogTcm@selectGlobalStore", 206 | "branch":"self", 207 | "params":{ 208 | "lslId":lslId, 209 | "myCampus":"Y" 210 | } 211 | } 212 | response = session.post(url=url,json=payload,headers=login_success_headers) 213 | DetailedInfoList = json.loads(response.text)["value"] 214 | 215 | for item in DetailedInfoList: 216 | print("========================================================================") 217 | name = item["lessonSegment"]["fullName"].encode("gbk") 218 | lsltId = item["lsltId"].encode("gbk") 219 | print("%-15s %-40s"%(lsltId,name)) 220 | 221 | for schedule in item["teachClassMaster"]["lessonSchedules"]: 222 | room = schedule["classroom"]["fullName"] 223 | time = schedule["timeBlock"]["name"] 224 | print("%s %s"%(room.encode("gbk"),time.encode("gbk"))) 225 | for teacher in item["teachClassMaster"]["lessonTeachers"]: 226 | teacher_name = teacher["teacher"]["name"] 227 | print("teacher: %s "%teacher_name.encode("gbk")) 228 | return 229 | #添加到选课列表 230 | def AddToSelList(session,aplId): 231 | url = 'https://uims.jlu.edu.cn/ntms/action/select/add-gx-lsl.do' 232 | payload = { 233 | #这里应该是一次可以添加好几个 234 | "aplIds":[ 235 | aplId 236 | ], 237 | "splanId":splanId, 238 | "studId":stuId, 239 | "isQuick":False 240 | } 241 | response = session.post(url=url,json=payload,headers=login_success_headers) 242 | print(response.text) 243 | #从选课列表删除 244 | def DelFromSelList(session,lslId): 245 | url = "https://uims.jlu.edu.cn/ntms/action/select/delete-other-lsl.do" 246 | payload={ 247 | "lslId":lslId 248 | } 249 | response = session.post(url=url,json=payload,headers=login_success_headers) 250 | print(response.text) 251 | 252 | 253 | Selecting={} 254 | ignore_error = True 255 | Counter = {} 256 | #线程函数选课 257 | def fuck(session,lsltId): 258 | while True: 259 | #获取课程状态 260 | statu = Selecting[lsltId] 261 | #正在选择 262 | if statu == "doing": 263 | result = SelectIt(session,lsltId) 264 | #判断结果.0:选课成功 265 | # 1410:已经选过该课程了 266 | # 1420:该课程已经选过其他教学班 267 | if result == 0 or result == 1410 or result == 1420: 268 | if Selecting[lsltId] == 'doing': 269 | Selecting[lsltId] = "ok" 270 | SelectLogLock.acquire() 271 | print("[#]The lesson(%s) has be selected successfully!."%lsltId) 272 | SelectLogLock.release() 273 | break 274 | #1932选课已经结束, 275 | if result == 1932 : 276 | SelectLogLock.acquire() 277 | print("[x]Sorry. The time for selecting courses has ended!") 278 | SelectLogLock.release() 279 | break 280 | #1931选课还未开始,如果不忽略错误,那么退出 281 | if result == 1931 and ignore_error == False: 282 | SelectLogLock.acquire() 283 | print("[x]Sorry. It's not time to choose classes yet!.") 284 | SelectLogLock.release() 285 | break 286 | #其他错误,不处理,继续尝试 287 | else: 288 | #已经选上了 289 | break 290 | Counter["WorkingThread"]-=1 291 | ''' 292 | 大致流程是: 293 | 获取课程列表,然后通过aplId 加入到选课列表. 294 | 获取选课列表的内容,得到课程的lslId 295 | 在页面上点击课程后,会出来详细的信息,也就是lsltId了,选课的时候就用这个去选. 296 | aplId--->lslId--->lsltId---->SelectIt. 297 | ''' 298 | 299 | #输入用户账号和密码 300 | #emmmm突然在Js代码里面找到了这部分 ThansferPwd = MD5("UIMS"+username+password) 301 | print "Please input username:", 302 | username = raw_input() 303 | password = getpass.getpass("Please input password:") 304 | ThansferPwd = hashlib.md5("UIMS"+username+password).hexdigest() 305 | #登录 306 | session = login(username=username,password=ThansferPwd) 307 | if session is None: 308 | exit() 309 | 310 | #获取stuId 311 | print("[*]Get StuId...") 312 | info = GetMyInfo(session) 313 | stuId = info["value"][0]["studId"] 314 | print("[#]stuId: %d"%stuId) 315 | 316 | #获取选课信息 317 | print("[*]Get Sel Lesson Info...") 318 | SelInfo = GetSelLesInfo(session) 319 | print("====================================================================") 320 | print("\t\t@start time: %s"%SelInfo["value"][0]["currStartTime"].encode("gbk")) 321 | print("\t\t@stop time: %s"%SelInfo["value"][0]["currStopTime"].encode("gbk")) 322 | print("\t\t@title : %s"%SelInfo["value"][0]["title"].encode("gbk")) 323 | 324 | splanId = SelInfo["value"][0]["splanId"] 325 | termId = SelInfo["value"][0]["teachingTerm"]["termId"] 326 | 327 | print("\t\t@splanId: %d\ttermId: %d"%(splanId,termId)) 328 | 329 | while True: 330 | print("====================================================================") 331 | print("\t\t1.Print all courses") 332 | print("\t\t2.Add to select list") 333 | print("\t\t3.Del from select list") 334 | print("\t\t4.Print select list") 335 | print("\t\t5.Print detailed course information") 336 | print("\t\t6.List of selected courses") 337 | print("\t\t7.Fuck it") 338 | print("\t\t8.Cancel it") 339 | print("\t\t9.exit") 340 | print("====================================================================") 341 | print "please input choice >", 342 | choice = input() 343 | id = int(choice) 344 | if id == 1: 345 | #输出课程列表 346 | print("====================================================================") 347 | print("[#]All courses:") 348 | PrintAllLessons(session) 349 | 350 | if id == 2: 351 | #添加到选课列表 352 | print "please input aplId >", 353 | aplId = int(input()) 354 | AddToSelList(session,aplId) 355 | 356 | if id == 3: 357 | #从选课列表删除 358 | print "Please input lslId >", 359 | lslId = int(input()) 360 | DelFromSelList(session,lslId) 361 | 362 | if id == 4: 363 | #输出选课列表 364 | print("====================================================================") 365 | print("[#]Select List") 366 | PrintMySelList(session) 367 | 368 | if id == 5: 369 | #打印课程详细信息 370 | print "Please input lslId >", 371 | lslId = int(input()) 372 | GetLesDetailedInfo(session,lslId) 373 | if id == 6: 374 | #打印已选课程列表 375 | print("====================================================================") 376 | print("[#]List of selected courses:") 377 | PrintMySelectedList(session) 378 | if id == 7: 379 | Counter["WorkingThread"] = 0 380 | #选课 381 | print "Please input lsltIds >", 382 | lsltids = raw_input() 383 | pattern = "(\d+)" 384 | for lsltid in re.findall(pattern=pattern,string=lsltids): 385 | Selecting[lsltid] = "doing" 386 | 387 | print lsltid,"Selecting......\n" 388 | for i in range(8): 389 | Counter["WorkingThread"]+=1 390 | thread.start_new_thread(fuck,(session,lsltid)) 391 | 392 | while Counter["WorkingThread"]>0: 393 | time.sleep(1) 394 | if id == 8: 395 | #退课 396 | print "Please input lsltId >", 397 | lsltid = input() 398 | CancelIt(session,lsltid) 399 | 400 | if id == 9: 401 | break 402 | 403 | session.close() 404 | -------------------------------------------------------------------------------- /old/fucklesson_vpn.py: -------------------------------------------------------------------------------- 1 | import time 2 | import requests 3 | import json 4 | from bs4 import BeautifulSoup 5 | import random 6 | import threading 7 | import os 8 | import re 9 | import hashlib 10 | import getpass 11 | 12 | class Uims: 13 | def __init__(self,session): 14 | self.s = session 15 | self.login_success_headers = { 16 | 'Host': 'uims.jlu.edu.cn', 17 | 'Origin': 'https://uims.jlu.edu.cn', 18 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62', 19 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 20 | 'Referer': 'https://uims.jlu.edu.cn/ntms/index.do', 21 | } 22 | self.ignore_not_start = True 23 | self.Selecting={} 24 | self.mutex = threading.Lock() 25 | self.stuId = '' 26 | self.splanId = 0 27 | self.termId = 0 28 | 29 | pass 30 | 31 | def login(self,username,password): 32 | verification_code = 'https://uims.jlu.edu.cn/ntms/open/get-captcha-image.do?s='+str(random.random()) 33 | login_auth = "https://uims.jlu.edu.cn/ntms/j_spring_security_check" 34 | #下载验证码 35 | headers = { 36 | 'Host': 'uims.jlu.edu.cn', 37 | "Referer": "https://uims.jlu.edu.cn/ntms/", 38 | "User-Agent" : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62", 39 | "Origin": "https://uims.jlu.edu.cn" 40 | } 41 | 42 | print("[*]downloading the verification code...") 43 | verification_code_res = self.s.get(url = verification_code,headers=headers) 44 | with open("./vcode.png","wb") as file: 45 | file.write(verification_code_res.content) 46 | 47 | os.startfile("vcode.png") 48 | #让用户自己输入验证码 49 | print("[#]please input vcode >",end='') 50 | vcode = str(input()) 51 | #登录 52 | print("[*]login....") 53 | #表单方式提交,不是json 54 | 55 | payload = { 56 | "username":username, 57 | "password":hashlib.md5(("UIMS"+username+password).encode('utf-8')).hexdigest(), 58 | "mousePath":"", 59 | "vcode": vcode 60 | } 61 | cookies = { 62 | "loginPage":"userLogin.jsp", 63 | "alu":username, 64 | "pwdStrength":"3" 65 | } 66 | headers={ 67 | 'Host': 'uims.jlu.edu.cn', 68 | 'Origin': 'https://uims.jlu.edu.cn', 69 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36 Edg/96.0.1054.62', 70 | 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9', 71 | 'Referer': 'https://uims.jlu.edu.cn/ntms/userLogin.jsp', 72 | } 73 | response = self.s.post(data=payload,url = login_auth,headers=headers,cookies=cookies) 74 | #登录成功会重定向到index.do 75 | if response.status_code == 200 and response.url[-9:] == "/index.do": 76 | print("[#]login success!") 77 | #获取stuid 78 | self.stuId = self.get_my_info()["value"][0]["studId"] 79 | #获取 splanId 和term id 80 | try: 81 | SelInfo = self.get_sel_lesson_info() 82 | print("====================================================================") 83 | print("\t\t@start time: %s"%SelInfo["value"][0]["currStartTime"]) 84 | print("\t\t@stop time: %s"%SelInfo["value"][0]["currStopTime"]) 85 | print("\t\t@title : %s"%SelInfo["value"][0]["title"]) 86 | 87 | self.splanId = SelInfo["value"][0]["splanId"] 88 | self.termId = SelInfo["value"][0]["teachingTerm"]["termId"] 89 | except: 90 | print("当前无选课信息") 91 | exit(0) 92 | pass 93 | return True 94 | else: 95 | print("[x]login failed!") 96 | return False 97 | 98 | def get_my_info(self): 99 | url = "https://uims.jlu.edu.cn/ntms/service/res.do" 100 | payload={ 101 | "tag":"studInfoAll@student", 102 | "branch":"self", 103 | "params":{} 104 | } 105 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 106 | return json.loads(response.text) 107 | 108 | #获取选课信息 109 | def get_sel_lesson_info(self): 110 | url ="https://uims.jlu.edu.cn/ntms/service/res.do" 111 | payload = { 112 | "tag":"common@selectPlan", 113 | "branch":"byStudentSet", 114 | "params":{ 115 | "studId":self.stuId 116 | } 117 | } 118 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 119 | return json.loads(response.text) 120 | 121 | #打印全部课程(供选择的课) 122 | def PrintAllLessons(self): 123 | url = "https://uims.jlu.edu.cn/ntms/service/res.do" 124 | payload={ 125 | "type":"search", 126 | "tag":"apl@gxSelect", 127 | "branch":"default", 128 | "params":{ 129 | #"mooc":"Y", #慕课在线课程 130 | "campus":"1401", #应该是校区,1401貌似是前卫南区 131 | "splanId":self.splanId, #这里可能需要修改 132 | "termId":self.termId #这里可能需要修改 133 | }, 134 | "orderBy":"lesson.courseInfo.courName" 135 | } 136 | 137 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 138 | LessonList = json.loads(response.text)["value"] 139 | 140 | print ("%-11s %-45s %-45s"%("aplId","CourseName","SchoolName")) 141 | for item in LessonList: 142 | aplId = item["aplId"] 143 | name = item['lesson']['courseInfo']['courName'] 144 | school = item['lesson']['teachSchool']['schoolName'] 145 | print ("%-11d %-45s %-45s"%(aplId,name,school)) 146 | 147 | #输出选课列表(包含未选课程) 148 | def PrintMySelList(self): 149 | url = 'https://uims.jlu.edu.cn/ntms/service/res.do' 150 | payload = { 151 | "tag":"lessonSelectLog@selectStore", 152 | "branch":"default", 153 | "params":{ 154 | "splanId":self.splanId 155 | } 156 | } 157 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 158 | LessonList = json.loads(response.text)["value"] 159 | 160 | print ("%-11s%-45s%-45s%-45s"%("lslId","CourseName","SchoolName","Y/N")) 161 | for item in LessonList: 162 | lslId = item["lslId"] 163 | name = item['lesson']['courseInfo']['courName'] 164 | school = item['lesson']['teachSchool']['schoolName'] 165 | selected = item["selectResult"] 166 | print ("%-11d%-45s%-45s%-45s"%(lslId,name,school,selected)) 167 | 168 | #输出已选课程列表 169 | def PrintMySelectedList(self): 170 | url = 'https://uims.jlu.edu.cn/ntms/service/res.do' 171 | payload = { 172 | "tag":"teachClassStud@schedule", 173 | "branch":"self", 174 | "params":{ 175 | "termId":self.termId 176 | } 177 | } 178 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 179 | LessonList = json.loads(response.text)["value"] 180 | for item in LessonList: 181 | name = item["teachClassMaster"]["lessonSegment"]["fullName"] 182 | print("%s "%name.encode("gbk")) 183 | for teacher in item["teachClassMaster"]["lessonTeachers"]: 184 | print("\t\t%s"%teacher["teacher"]["name"].encode("gbk")) 185 | 186 | #选课 187 | def SelectIt(self,lsltId): 188 | url = 'https://uims.jlu.edu.cn/ntms/action/select/select-lesson.do' 189 | payload = { 190 | "lsltId":lsltId, 191 | "opType":"Y" #同时添加到快捷选课? 192 | } 193 | #加个超时,要不然卡住了 194 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers,timeout=1) 195 | result = json.loads(response.text) 196 | 197 | print("errno: %d msg:%s"%(result["errno"],result["msg"])) 198 | return result["errno"] 199 | 200 | #退课 201 | def CancelIt(self,lsltId): 202 | url = 'https://uims.jlu.edu.cn/ntms/action/select/select-lesson.do' 203 | payload = { 204 | "lsltId":lsltId, 205 | "opType":"N" 206 | } 207 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 208 | result = json.loads(response.text) 209 | print("errno: %d msg:%s"%(result["errno"],result["msg"].encode("gbk"))) 210 | return result["errno"] 211 | 212 | #获取课程的详细信息:有哪些老师授课, 213 | def GetLesDetailedInfo(self,lslId): 214 | url = 'https://uims.jlu.edu.cn/ntms/service/res.do' 215 | payload = { 216 | "tag":"lessonSelectLogTcm@selectGlobalStore", 217 | "branch":"self", 218 | "params":{ 219 | "lslId":lslId, 220 | "myCampus":"Y" 221 | } 222 | } 223 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 224 | DetailedInfoList = json.loads(response.text)["value"] 225 | 226 | for item in DetailedInfoList: 227 | print("==============================================================") 228 | name = item["lessonSegment"]["fullName"] 229 | lsltId = item["lsltId"] 230 | print("%-15s %-40s"%(lsltId,name)) 231 | 232 | for schedule in item["teachClassMaster"]["lessonSchedules"]: 233 | room = schedule["classroom"]["fullName"] 234 | time = schedule["timeBlock"]["name"] 235 | print("%s %s"%(room,time)) 236 | for teacher in item["teachClassMaster"]["lessonTeachers"]: 237 | teacher_name = teacher["teacher"]["name"] 238 | print("teacher: %s "%teacher_name) 239 | return 240 | #添加到选课列表 241 | def AddToSelList(self,aplId): 242 | url = 'https://uims.jlu.edu.cn/ntms/action/select/add-gx-lsl.do' 243 | payload = { 244 | #这里应该是一次可以添加好几个 245 | "aplIds":[ 246 | aplId 247 | ], 248 | "splanId":self.splanId, 249 | "studId":self.stuId, 250 | "isQuick":False 251 | } 252 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 253 | print(response.text) 254 | #从选课列表删除 255 | def DelFromSelList(self,lslId): 256 | url = "https://uims.jlu.edu.cn/ntms/action/select/delete-other-lsl.do" 257 | payload={ 258 | "lslId":lslId 259 | } 260 | response = self.s.post(url=url,json=payload,headers=self.login_success_headers) 261 | print(response.text) 262 | 263 | def Run(self): 264 | while True: 265 | os.system('cls') 266 | print("========================================================") 267 | print("\t\t1.Print all courses") 268 | print("\t\t2.Add to select list") 269 | print("\t\t3.Del from select list") 270 | print("\t\t4.Print select list") 271 | print("\t\t5.Print detailed course information") 272 | print("\t\t6.List of selected courses") 273 | print("\t\t7.Fuck it") 274 | print("\t\t8.Cancel it") 275 | print("========================================================") 276 | print("please input choice >",end="") 277 | id = 0 278 | try: 279 | id = int(input()) 280 | except: 281 | continue 282 | 283 | if id == 1: 284 | #输出课程列表 285 | print("====================================================================") 286 | print("[#]All courses:") 287 | self.PrintAllLessons() 288 | 289 | if id == 2: 290 | #添加到选课列表 291 | aplId = int(input("please input aplId >")) 292 | self.AddToSelList(aplId) 293 | 294 | if id == 3: 295 | #从选课列表删除 296 | lslId = int(input("Please input lslId >")) 297 | self.DelFromSelList(lslId) 298 | 299 | if id == 4: 300 | #输出选课列表 301 | print("====================================================================") 302 | print("[#]Select List") 303 | self.PrintMySelList() 304 | 305 | if id == 5: 306 | lslId = int(input("Please input lslId >")) 307 | self.GetLesDetailedInfo(lslId) 308 | if id == 6: 309 | #打印已选课程列表 310 | print("====================================================================") 311 | print("[#]List of selected courses:") 312 | self.PrintMySelectedList() 313 | 314 | if id == 7: 315 | #选课 316 | lsltids = input("Please input lsltIds >") 317 | pattern = "(\d+)" 318 | 319 | Works = {} 320 | for lsltid in re.findall(pattern=pattern,string=lsltids): 321 | Works[lsltid] = {} 322 | 323 | for i in range(8): #每一个课开8个线程去强. 324 | Works[lsltid][i] = threading.Thread(target = self.Fuck,args = (lsltid,)) 325 | Works[lsltid][i].start() 326 | 327 | for key in Works: 328 | for i in range(8): 329 | Works[key][i].join() 330 | 331 | if id == 8: 332 | lsltid = input("Please input lsltId >") 333 | self.CancelIt(lsltid) 334 | 335 | def Fuck(self,lsltId): 336 | while True: 337 | #获取课程状态 338 | statu = self.Selecting.get(lsltId) 339 | if statu == None: 340 | break 341 | #正在选择 342 | if statu == "doing": 343 | result = self.SelectIt(lsltId) 344 | #判断结果.0:选课成功 345 | # 1410:已经选过该课程了 346 | # 1420:该课程已经选过其他教学班 347 | if result == 0 or result == 1410 or result == 1420: 348 | self.mutex.acquire() 349 | 350 | if self.Selecting[lsltId] == 'doing': 351 | self.Selecting[lsltId] = "ok" 352 | print("[#]The lesson(%s) has be selected successfully!."%lsltId) 353 | 354 | self.mutex.release() 355 | break 356 | 357 | #1932选课已经结束, 358 | if result == 1932 : 359 | print("[x]Sorry. The time for selecting courses has ended!") 360 | break 361 | #1931选课还未开始,如果不忽略错误,那么退出 362 | if result == 1931 and self.ignore_not_start == False: 363 | print("[x]Sorry. It's not time to choose classes yet!.") 364 | break 365 | #其他错误,不处理,继续尝试 366 | else: 367 | break 368 | 369 | ''' 370 | 大致流程是: 371 | 获取课程列表,然后通过aplId 加入到选课列表. 372 | 373 | 获取选课列表的内容,得到课程的lslId 374 | 在页面上点击课程后,会出来详细的信息,也就是lsltId了,选课的时候就用这个去选. 375 | aplId--->lslId--->lsltId---->SelectIt. 376 | ''' 377 | 378 | class VpnSession: 379 | 380 | def __init__(self): 381 | self.Session = requests.session() 382 | self.redirect_url = '' 383 | self.url = '' 384 | 385 | def login(self,username,password)->bool: 386 | index = 'https://webvpn.jlu.edu.cn/' 387 | login_url = 'https://webvpn.jlu.edu.cn/login' 388 | 389 | headers = { 390 | 'Host': 'webvpn.jlu.edu.cn', 391 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62' 392 | 393 | } 394 | #get captcha_id 395 | html = BeautifulSoup(self.Session.get(url=index,headers=headers).text,'html.parser') 396 | captcha_id = '' 397 | for input in html.find_all('input'): 398 | name = '' 399 | try: 400 | name = input['name'] 401 | except: 402 | pass 403 | else: 404 | if input['name'] == 'captcha_id': 405 | captcha_id = input['value'] 406 | break 407 | 408 | #print(captcha_id) 409 | #login 410 | headers = { 411 | 'Origin': 'https://webvpn.jlu.edu.cn', 412 | 'Referer': 'https://webvpn.jlu.edu.cn/login', 413 | 'X-Requested-With': 'XMLHttpRequest', 414 | 'Host': 'webvpn.jlu.edu.cn', 415 | 'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8', 416 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62' 417 | } 418 | post_url = 'https://webvpn.jlu.edu.cn/do-login' 419 | data = 'auth_type=local' 420 | data += '&username=' + username 421 | data += '&sms_code=' 422 | data += '&password=' + password 423 | data += '&captcha=' 424 | data += '&needCaptcha=false' 425 | data += '&captcha_id=' + captcha_id 426 | 427 | success = json.loads(self.Session.post(url = post_url,data=data,headers=headers).text)['success'] 428 | 429 | headers = { 430 | 'Origin': 'https://webvpn.jlu.edu.cn', 431 | 'Referer': 'https://webvpn.jlu.edu.cn/login', 432 | 'Host': 'webvpn.jlu.edu.cn', 433 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62' 434 | } 435 | self.Session.get(url = index,headers = headers).url 436 | 437 | return success 438 | 439 | def redirect(self,name): 440 | get_url = 'https://webvpn.jlu.edu.cn/user/portal_groups?_t=' + str(time.time()).split('.')[0] + '224' 441 | headers = { 442 | 'Host': 'webvpn.jlu.edu.cn', 443 | 'Referer': 'https://webvpn.jlu.edu.cn/', 444 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62' 445 | 446 | } 447 | data = json.loads(self.Session.get(url = get_url,headers=headers).text) 448 | 449 | for a in data['data']: 450 | if a['group']['group_name'] == '学生资源': 451 | for b in a['resource']: 452 | if b['name'] == name: 453 | self.redirect_url = b['redirect'] 454 | if 'https' not in b['url']: 455 | self.url = b['url'].replace('http','https') 456 | else: 457 | self.url = b['url'] 458 | 459 | return True 460 | return False 461 | 462 | def action(self,method,url,cookies,headers,data,json): 463 | new_url = 'https://webvpn.jlu.edu.cn' + url.replace(self.url + '/',self.redirect_url) 464 | new_headers = { 465 | 'Host': 'webvpn.jlu.edu.cn', 466 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.114 Safari/537.36 Edg/103.0.1264.62' 467 | } 468 | #替换 Host 469 | if headers != None: 470 | for key in headers: 471 | # 重新设置下面这些header 472 | if key == 'Referer': 473 | new_headers['Referer'] ='https://webvpn.jlu.edu.cn' + headers.get('Referer').replace(self.url + '/',self.redirect_url) 474 | continue 475 | if key == 'Origin': 476 | new_headers['Origin'] ='https://webvpn.jlu.edu.cn' 477 | #将没有的header 加到 new_headers 478 | if new_headers.get(key) == None: 479 | new_headers[key] = headers[key] 480 | 481 | if method == 'get': 482 | return self.Session.get(new_url,headers=new_headers,cookies=cookies,data=data) 483 | if method =='post': 484 | return self.Session.post(url=new_url,data=data,headers=new_headers,cookies=cookies,json=json) 485 | 486 | 487 | 488 | def get(self,url,headers=None,cookies = None,data=None): 489 | return self.action('get',url,cookies,headers,data,json=None) 490 | 491 | def post(self,url,headers=None,cookies = None,data=None,json=None): 492 | return self.action('post',url,cookies,headers,data,json=json) 493 | 494 | if __name__ == '__main__': 495 | choice = input("Enable Vpn?(Y/y) :") 496 | Session = None 497 | 498 | if choice == 'Y' or choice == 'y': 499 | Session = VpnSession() 500 | print("Vpn Login") 501 | 502 | username= input("Username > ") 503 | password = getpass.getpass() 504 | 505 | if False == Session.login(username,password): 506 | print('login vpn failed!') 507 | exit(0) 508 | 509 | if False == Session.redirect('本科教务管理系统'): 510 | print('redirect failed!') 511 | exit(0) 512 | print('Vpn Init Success!') 513 | else: 514 | Session = requests.session() 515 | 516 | uims = Uims(Session) 517 | print("Uims Login") 518 | 519 | username = input('Username > ') 520 | password = getpass.getpass() 521 | 522 | if True == uims.login(username=username,password=password): 523 | uims.Run() 524 | else: 525 | print("Uims login Failed!") 526 | 527 | 528 | -------------------------------------------------------------------------------- /requirement.txt: -------------------------------------------------------------------------------- 1 | requests 2 | ddddocr 3 | pycryptodomex 4 | 5 | --------------------------------------------------------------------------------