cuit.py 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3. '''
  4. @Contact : liuyuqi.gov@msn.cn
  5. @Time : 2022/05/31 01:04:55
  6. @License : Copyright © 2017-2022 liuyuqi. All Rights Reserved.
  7. @Desc : cuit.edu.cn 自动选课
  8. '''
  9. from asyncio.log import logger
  10. import platform
  11. from auto_cuit.libs.json_conf import JsonConf
  12. from auto_cuit import api
  13. import requests
  14. import os
  15. import sys
  16. import re
  17. import json
  18. import time
  19. import random
  20. class Cuit(object):
  21. def __init__(self, configPath="conf/config.josn"):
  22. self.sess = requests.session()
  23. self.conf = JsonConf(configPath)
  24. self.sess.cookies = self.conf.data['cookies']
  25. self.sess.headers = {
  26. "X-Requested-With": "XMLHttpRequest",
  27. "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.0 Safari/537.36 Edg/84.0.521.0"
  28. }
  29. def run(self):
  30. profiledId = self.conf.data['profiled_id']
  31. courseName = self.conf.data['course_name']
  32. # 验证码
  33. cnt = 0
  34. while True:
  35. pic = self.getCaptcha()
  36. ocrResult = self.postOCRPic(pic)
  37. print('OCR: ' + ocrResult['result'])
  38. checkResult = self.checkCaptcha(ocrResult['result'], profiledId)
  39. if checkResult:
  40. break
  41. cnt += 1
  42. time.sleep(0.5)
  43. if cnt % 5 == 0:
  44. print('验证码错误次数过多, 等待5秒')
  45. time.sleep(5)
  46. print('验证码检测通过,等待1秒')
  47. time.sleep(1)
  48. # 检测开放状态
  49. print('获取lessonId')
  50. lessonId = self.courseName2Id(profiledId, courseName)
  51. if lessonId == None:
  52. print('没有找到相关课程:' + courseName)
  53. exit(1)
  54. print('检测选课开放状态')
  55. cnt = 0
  56. while True:
  57. if self.isAvailable(ocrResult['result'], profiledId):
  58. break
  59. pass
  60. cnt += 1
  61. print('没有到选课时间,等待5秒 - ' + str(cnt))
  62. time.sleep(5)
  63. # 抢课
  64. print('开始抢课')
  65. i = 0
  66. while True:
  67. i += 1
  68. print(i)
  69. if self.fuckCourse(str(profiledId), str(lessonId)):
  70. break
  71. time.sleep(0.5)
  72. if i >= 20:
  73. i = 0
  74. if platform.system().lower() == 'linux':
  75. os.system("clear")
  76. elif platform.system().lower() == 'windows':
  77. os.system("cls")
  78. pass
  79. pass
  80. pass
  81. def fuckCourse(self, profiledId, lessonId):
  82. try:
  83. body = {
  84. "optype": "true",
  85. "operator0": lessonId + ":true:0",
  86. "lesson0": lessonId,
  87. "schLessonGroup_" + lessonId: "undefined"
  88. }
  89. req = requests.post(api.chooseCourse % profiledId,
  90. data=body, timeout=5, allow_redirects=False)
  91. req.encoding = 'utf-8'
  92. html = req.text
  93. ret = re.search(r"margin:auto;\">\n\t\t\t\t(.*)<\/br>", html)
  94. if ret == None:
  95. print("cookie过期")
  96. exit(-1)
  97. pass
  98. print(ret.group(1))
  99. req.close()
  100. if '成功' in ret.group(1):
  101. print('get')
  102. return True
  103. except Exception as err:
  104. print("出错")
  105. print(err)
  106. return False
  107. pass
  108. pass
  109. def getCaptcha(self):
  110. try:
  111. picReq = self.sess.get(url=api.getCaptcha, timeout=5)
  112. except Exception as err:
  113. print(err)
  114. return picReq.content
  115. def postOCRPic(self, pic):
  116. url = self.ocrServer
  117. files = {'captcha': pic}
  118. data = {
  119. 'enctype': 'multipart/form-data',
  120. 'name': 'captcha'
  121. }
  122. ocrReq = requests.post(url=url, data=data, files=files)
  123. return json.loads(ocrReq.content)
  124. def checkCaptcha(self, captcha, profiledId):
  125. data = {
  126. 'captcha_response': captcha,
  127. 'electionProfile.id': profiledId
  128. }
  129. try:
  130. checkReq = requests.post(
  131. url=api.checkCode, data=data, allow_redirects=False, timeout=5)
  132. except Exception as err:
  133. logger.error(err)
  134. # print(checkReq.text)
  135. # 未登录与验证码错误都是302,但Location去向不同
  136. if checkReq.status_code == 200:
  137. return True
  138. elif 'sso' in checkReq.headers['Location']:
  139. # 转到统一登录中心
  140. print('cookie失效!!!')
  141. exit(1)
  142. return False
  143. def isAvailable(self, captcha, profiledId):
  144. '''
  145. 检测登录状态
  146. '''
  147. data = {
  148. 'captcha_response': captcha,
  149. 'electionProfile.id': profiledId
  150. }
  151. try:
  152. checkReq = self.sess.post(
  153. url=api.checkCode, data=data, allow_redirects=False, timeout=5)
  154. # 未登录与验证码错误都是302,但Location去向不同
  155. if checkReq.status_code == 200:
  156. return '不在选课时间内' not in checkReq.text
  157. elif 'sso' in checkReq.headers['Location']:
  158. # 转到统一登录中心
  159. print('cookie失效')
  160. False
  161. except Exception as err:
  162. logger.error(err)
  163. return False
  164. return False
  165. def courseName2Id(self, profileId, courseName):
  166. try:
  167. courseListReq = self.sess.get(
  168. url=api.getCourseList % str(profileId), allow_redirects=False, timeout=5)
  169. except Exception as err:
  170. print(err)
  171. courseList = courseListReq.text
  172. jsData = execjs.compile(courseList)
  173. lessonJSONs = jsData.eval('lessonJSONs')
  174. # print(lessonJSONs)
  175. for lesson in lessonJSONs:
  176. if courseName in lesson['name']:
  177. return lesson['id']
  178. return None