examInf.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. """
  2. 接口
  3. """
  4. import os
  5. import time
  6. import bs4
  7. import requests
  8. import common
  9. import config
  10. import warnings
  11. warnings.filterwarnings("ignore")
  12. errCount = 0
  13. def calctime(m_func):
  14. def decorter(*args, **kwargs):
  15. start = time.time()
  16. res = m_func(*args, **kwargs)
  17. end = time.time()
  18. # print(m_func.__name__+" spend time is "+str(end-start))
  19. return res
  20. return decorter
  21. @calctime
  22. def login():
  23. url = "https://" + config.domain + "/api/ecs_core/auth/login"
  24. data = {"rootOrgId": None, "domain": config.domain.replace("exam-cloud.cn", "ecs.qmth.com.cn"),
  25. "accountType": "COMMON_LOGIN_NAME", "accountValue": config.username, "password": config.password,
  26. "smsCode": None}
  27. result = requests.post(url, json=data, verify=False)
  28. if result.status_code == 200:
  29. config.header = {
  30. "key": result.json()["key"],
  31. "token": result.json()['token']
  32. }
  33. config.rootOrgId = result.json()["rootOrgId"]
  34. print('登录成功!')
  35. else:
  36. print('登录失败,请检查配置参数或网络是否正常!')
  37. raise Exception("登录失败")
  38. @calctime
  39. def doExport():
  40. print('')
  41. if len(config.examIds) == 0:
  42. print("配置参数“examIds”不能为空!")
  43. return None
  44. login()
  45. print('examIds:' + config.examIds)
  46. print('courseIds:' + config.courseIds)
  47. print('queryStudentCodes:' + config.queryStudentCodes)
  48. print('skipStudentCodes:' + config.skipStudentCodes)
  49. print('useStudentCodePath:' + config.useStudentCodePath)
  50. print('outputPath:' + config.outputpath)
  51. examIds = config.examIds.split(',')
  52. for examId in examIds:
  53. if len(config.courseIds) > 0:
  54. courseIds = config.courseIds.split(',')
  55. for courseId in courseIds:
  56. if len(config.queryStudentCodes) > 0:
  57. studentCodes = config.queryStudentCodes.split(',')
  58. for studentCode in studentCodes:
  59. querydetail(1, examId, courseId, studentCode)
  60. else:
  61. querydetail(1, examId, courseId, None)
  62. else:
  63. if len(config.queryStudentCodes) > 0:
  64. studentCodes = config.queryStudentCodes.split(',')
  65. for studentCode in studentCodes:
  66. querydetail(1, examId, None, studentCode)
  67. else:
  68. querydetail(1, examId, None, None)
  69. print('')
  70. print("全部执行完成,失败数:" + str(errCount))
  71. @calctime
  72. def querydetail(curpage, examId, courseId, studentCode):
  73. print('')
  74. global errCount
  75. url = "https://" + config.domain + "/api/ecs_oe_admin/exam/record/detail/list"
  76. params = {"rootOrgId": config.rootOrgId, "examRecordDataId": None, "hasStranger": None, "courseId": courseId,
  77. "courseLevel": None,
  78. "examId": examId, "faceSuccessPercentLower": None, "faceSuccessPercentUpper": None,
  79. "identityNumber": None,
  80. "orgId": None, "studentCode": studentCode, "studentName": None, "isWarn": None, "pageNo": curpage,
  81. "pageSize": 500,
  82. "startTime": None, "endTime": None, "infoCollector": None, "hasVirtual": None, "ORG_FIND_ALL": True,
  83. "examStageId": "", "examType": "ONLINE"}
  84. result = requests.post(url, json=params, headers=config.header, verify=False)
  85. if result.status_code == 200:
  86. contents = result.json()["content"]
  87. totalPages = result.json()["totalPages"]
  88. totalElements = result.json()["totalElements"]
  89. print("---> totalElements=" + str(totalElements) + " totalPages=" + str(totalPages)
  90. + " curPage=" + str(curpage) + " examId=" + str(examId) + " courseId=" + str(courseId))
  91. for content in contents:
  92. try:
  93. solveexamRecord(examId, content)
  94. except Exception as e:
  95. errCount += 1
  96. print("网络异常,下载失败! " + content["courseCode"] + "_" + content["identityNumber"]
  97. + "_" + content["studentName"] + " 失败数:" + str(errCount))
  98. if curpage < totalPages:
  99. querydetail(curpage + 1, examId, courseId)
  100. else:
  101. raise Exception("获取数据失败,请检查配置参数或网络是否正常!")
  102. @calctime
  103. def findExamRecordDataEntity(examRecordId):
  104. url = "https://" + config.domain + "/api/ecs_oe_admin/exam/record/data/findExamRecordDataEntity"
  105. params = {
  106. "examRecordDataId": examRecordId
  107. }
  108. result = requests.get(url, params=params, headers=config.header, verify=False)
  109. # print(result.json())
  110. if result.status_code == 200:
  111. return result.json()
  112. else:
  113. # print(result.status_code)
  114. # print(result.json())
  115. return None
  116. @calctime
  117. def getExamRecordPaperStruct(examRecordDataId):
  118. url = "https://" + config.domain + "/api/ecs_oe_admin/examRecordPaperStruct/getExamRecordPaperStruct"
  119. params = {
  120. "examRecordDataId": examRecordDataId
  121. }
  122. result = requests.get(url, params=params, headers=config.header, verify=False)
  123. if result.status_code == 200:
  124. return result.json()
  125. else:
  126. return None
  127. @calctime
  128. def getExamRecordQuestions(examRecordDataId):
  129. url = "https://" + config.domain + "/api/ecs_oe_admin/examRecordQuestions/getExamRecordQuestions"
  130. params = {
  131. "examRecordDataId": examRecordDataId,
  132. "withScore": True,
  133. }
  134. result = requests.get(url, params=params, headers=config.header, verify=False)
  135. if result.status_code == 200:
  136. return result.json()
  137. else:
  138. return None
  139. @calctime
  140. def getQuesitons(examId, courseCode, groupCode, questionId):
  141. url = "https://" + config.domain + "/api/ecs_ques/default_question/question"
  142. data = {"examId": examId, "courseCode": courseCode, "groupCode": groupCode, "questionId": questionId}
  143. result = requests.post(url, json=data, headers=config.header, verify=False)
  144. if result.status_code == 200:
  145. return result.json()
  146. else:
  147. return None
  148. def solveexamRecord(examId, examRecorddetail):
  149. identityNumber = examRecorddetail["identityNumber"]
  150. studentName = examRecorddetail["studentName"]
  151. examrRecordDataId = examRecorddetail["id"]
  152. courseCode = examRecorddetail["courseCode"]
  153. courseName = examRecorddetail["courseName"]
  154. studentCode = examRecorddetail["studentCode"]
  155. if len(config.skipStudentCodes) > 0:
  156. # print(studentCode + ' ' + str(config.skipStudentCodes.find(studentCode)))
  157. if config.skipStudentCodes.find(studentCode) > -1:
  158. print("配置为跳过! " + courseCode + "_" + identityNumber + "_" + studentName + ".pdf")
  159. return None
  160. record = bs4.BeautifulSoup(
  161. open(common.resource_path(os.path.join("template", "template.html")), "r", encoding="utf-8"),
  162. features="html.parser")
  163. if config.useStudentCodePath == 'true':
  164. filepath = config.outputpath + os.sep + str(
  165. examId) + os.sep + courseCode + "_" + studentCode + "_" + studentName + ".pdf"
  166. else:
  167. filepath = config.outputpath + os.sep + str(
  168. examId) + os.sep + courseCode + "_" + identityNumber + "_" + studentName + ".pdf"
  169. if os.path.exists(filepath):
  170. print("已处理,跳过! " + courseCode + "_" + identityNumber + "_" + studentName + ".pdf")
  171. return None
  172. result = findExamRecordDataEntity(examrRecordDataId)
  173. # print(result)
  174. groupCode = result["examRecord"]["paperType"]
  175. defaultPaper = getExamRecordPaperStruct(examrRecordDataId)["defaultPaper"]
  176. papername = defaultPaper["name"]
  177. record.select_one("#paperName").string = str(papername)
  178. record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(1)").string = str(examrRecordDataId)
  179. record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(2)").string = str(studentCode)
  180. record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(3)").string = str(studentName)
  181. record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(4)").string = str(courseName) + "(" + str(
  182. courseCode) + ")"
  183. paperViewTag = record.select_one("#paperView")
  184. questionGroupList = defaultPaper["questionGroupList"]
  185. quesitonEntites = getExamRecordQuestions(examrRecordDataId)["examQuestionEntities"]
  186. main_number = 1
  187. sub_number = 1
  188. for questionGroup in questionGroupList:
  189. groupName = questionGroup["groupName"]
  190. groupScore = questionGroup["groupScore"]
  191. mainQuestionDiv = record.new_tag("div", attrs={"class": "mainQuestionDiv", "data-v-3575fe23": ""})
  192. paperViewTag.append(mainQuestionDiv)
  193. groupDiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "font-size: 16px; font-weight: bold;"})
  194. mainQuestionDiv.append(groupDiv)
  195. mainQuestionDiv.append(record.new_tag("div", attrs={"data-v-3575fe23": ""}))
  196. datadiv = record.new_tag("div", attrs={"data-v-3575fe23": ""})
  197. mainQuestionDiv.append(datadiv)
  198. datadiv1 = record.new_tag("div", attrs={"data-v-3575fe23": ""})
  199. datadiv.append(datadiv1)
  200. questionWrapperList = questionGroup["questionWrapperList"]
  201. groupDiv.string = common.four_to_han(str(main_number)) + "、" + groupName + "(" + str(groupScore) + "分" + ")"
  202. for questionWrapper in questionWrapperList:
  203. questionId = questionWrapper["questionId"]
  204. quesitondetail = getQuesitons(examId, courseCode, groupCode, questionId)
  205. main_body = record.new_tag("div",
  206. attrs={"data-v-3575fe23": "", "style": "display: flex; flex-direction: row;"})
  207. datadiv1.append(main_body)
  208. if quesitondetail["masterVersion"]["body"]:
  209. main_body_div = record.new_tag("div", attrs={"data-v-3575fe23": ""})
  210. main_body.append(main_body_div)
  211. soup = bs4.BeautifulSoup(quesitondetail["masterVersion"]["body"], features="html.parser")
  212. main_body_div.append(soup)
  213. questionUnitList = quesitondetail["masterVersion"]["questionUnitList"]
  214. for questionUnit in questionUnitList:
  215. questionType = questionUnit["questionType"]
  216. questiondiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "clear:both"})
  217. datadiv1.append(questiondiv)
  218. bodydiv = record.new_tag("div",
  219. attrs={"data-v-3575fe23": "", "style": "display: flex; flex-direction: row;"})
  220. questiondiv.append(bodydiv)
  221. sub_number_div = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"})
  222. sub_number_div.string = str(sub_number) + "、"
  223. content_div = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"})
  224. score_span = record.new_tag("span", attrs={"data-v-3575fe23": "", "style": "float:left"})
  225. bodydiv.append(sub_number_div)
  226. bodydiv.append(content_div)
  227. bodydiv.append(score_span)
  228. body = questionUnit["body"]
  229. soup = bs4.BeautifulSoup(body, features="html.parser")
  230. # content_div.append(str(sub_number)+"、")
  231. content_div.append(soup)
  232. rightAnswer = questionUnit["rightAnswer"]
  233. curRightAnswer = ''
  234. if rightAnswer and len(rightAnswer) > 0:
  235. curRightAnswer = rightAnswer[0]
  236. quesitonEntity = quesitonEntites[sub_number - 1]
  237. optionorder = quesitonEntity["optionPermutation"]
  238. questionScore = quesitonEntity["questionScore"]
  239. studentAnswer = quesitonEntity["studentAnswer"]
  240. studentScore = quesitonEntity["studentScore"]
  241. questionOptionList = questionUnit["questionOptionList"]
  242. score_span.string = "(" + str(questionScore) + "分)"
  243. if questionOptionList:
  244. option_idex = 0
  245. for option in optionorder:
  246. optiondetail = questionOptionList[option]
  247. optiondiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "clear:both"})
  248. datadiv1.append(optiondiv)
  249. optiondiv1 = record.new_tag("div", attrs={"data-v-3575fe23": "",
  250. "style": "display: flex; flex-direction: row;"})
  251. optiondiv.append(optiondiv1)
  252. optionIndexdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"})
  253. optiondiv1.append(optionIndexdiv)
  254. optionContentdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"})
  255. optiondiv1.append(optionContentdiv)
  256. optionIndexdiv.string = chr(65 + int(option_idex)) + "、"
  257. soup = bs4.BeautifulSoup(optiondetail["body"], features="html.parser")
  258. optionContentdiv.append(soup)
  259. option_idex = option_idex + 1
  260. answerdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "clear:both"})
  261. datadiv1.append(answerdiv)
  262. rightAnswerdiv = record.new_tag("div", attrs={"data-v-3575fe23": "",
  263. "style": "display: flex; flex-direction: row; color: green; font-weight: bold;"})
  264. rightAnswerdivtitle = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"})
  265. rightAnswerdivcontent = record.new_tag("span", attrs={"data-v-3575fe23": "", "style": "float:left"})
  266. answerdiv.append(rightAnswerdiv)
  267. rightAnswerdiv.append(rightAnswerdivtitle)
  268. rightAnswerdiv.append(rightAnswerdivcontent)
  269. rightAnswerdivtitle.string = "标准答案:"
  270. studentAnswerdiv = record.new_tag("div", attrs={"data-v-3575fe23": "",
  271. "style": "color: blue; font-weight: bold;clear:both"})
  272. answerdiv.append(studentAnswerdiv)
  273. studentAnswerdiv.string = "学生答案:"
  274. studentAnswercontentspan = record.new_tag("span", attrs={"data-v-3575fe23": ""})
  275. studentAnswerdiv.append(studentAnswercontentspan)
  276. if questionType == "SINGLE_CHOICE" or questionType == "MULTIPLE_CHOICE":
  277. correctAnswer = quesitonEntity["correctAnswer"]
  278. # print(correctAnswer,studentAnswer)
  279. rightAnswerdivcontent.append(
  280. selectorder(correctAnswer, optionorder))
  281. studentAnswercontentspan.append(
  282. selectorder(studentAnswer, optionorder))
  283. elif questionType == "TRUE_OR_FALSE":
  284. f = lambda x: "" if not x else "正确" if x == "true" else "错误"
  285. # print(f(curRightAnswer))
  286. rightAnswerdivcontent.append(f(curRightAnswer))
  287. studentAnswercontentspan.append(f(studentAnswer))
  288. else:
  289. rightAnswerdivcontent.append(
  290. bs4.BeautifulSoup(curRightAnswer if curRightAnswer else '', features="html.parser"))
  291. studentAnswercontentspan.append(
  292. bs4.BeautifulSoup(studentAnswer if studentAnswer else '', features="html.parser"))
  293. student_score_div = record.new_tag("div", attrs={"data-v-3575fe23": "",
  294. "style": "color: red; font-weight: bold;clear:both"})
  295. answerdiv.append(student_score_div)
  296. right_score_div_title = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"})
  297. right_score_div_title.string = "得分:"
  298. student_score_div.append(right_score_div_title)
  299. student_score_content_span = record.new_tag("span", attrs={"data-v-3575fe23": ""})
  300. if studentScore is None:
  301. student_score_content_span.string = "--分"
  302. else:
  303. student_score_content_span.string = str(studentScore) + "分"
  304. student_score_div.append(student_score_content_span)
  305. # print(main_number, " ", sub_number, " ", questionScore, " ", studentScore,
  306. # " ", rightAnswer, " ", studentAnswer)
  307. sub_number = sub_number + 1
  308. main_number = main_number + 1
  309. with open(common.resource_path(os.path.join("template", "temp.html")), 'w', encoding="utf-8") as fp:
  310. fp.write(record.prettify())
  311. if not os.path.exists(config.outputpath + os.sep + str(examId)):
  312. os.makedirs(config.outputpath + os.sep + str(examId))
  313. common.convert_to_pdf(common.resource_path(os.path.join("template", "temp.html")), filepath)
  314. print("已完成! " + courseCode + "_" + identityNumber + "_" + studentName + ".pdf examrRecordDataId=" + str(
  315. examrRecordDataId))
  316. def selectorder(answer, optionpremutation):
  317. if answer:
  318. answerstr = []
  319. for answerorder in answer:
  320. # print(optionpremutation)
  321. index = optionpremutation.index(int(answerorder))
  322. answerstr.append(chr(65 + index))
  323. answerstr.sort()
  324. return ",".join(answerstr)
  325. else:
  326. return ""