cuit.py 6.0 KB

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