""" 接口 """ import os import time import bs4 import requests import common import config import warnings warnings.filterwarnings("ignore") errCount = 0 def calctime(m_func): def decorter(*args, **kwargs): start = time.time() res = m_func(*args, **kwargs) end = time.time() # print(m_func.__name__+" spend time is "+str(end-start)) return res return decorter @calctime def login(): url = "https://" + config.domain + "/api/ecs_core/auth/login" data = {"rootOrgId": None, "domain": config.domain.replace("exam-cloud.cn", "ecs.qmth.com.cn"), "accountType": "COMMON_LOGIN_NAME", "accountValue": config.username, "password": config.password, "smsCode": None} result = requests.post(url, json=data, verify=False) if result.status_code == 200: config.header = { "key": result.json()["key"], "token": result.json()['token'] } config.rootOrgId = result.json()["rootOrgId"] print('登录成功!') else: print('登录失败,请检查配置参数或网络是否正常!') raise Exception("登录失败") @calctime def doExport(): print('') if len(config.examIds) == 0: print("配置参数“examIds”不能为空!") return None login() print('examIds:' + config.examIds) print('courseIds:' + config.courseIds) print('queryStudentCodes:' + config.queryStudentCodes) print('skipStudentCodes:' + config.skipStudentCodes) print('useStudentCodePath:' + config.useStudentCodePath) print('outputPath:' + config.outputpath) examIds = config.examIds.split(',') for examId in examIds: if len(config.courseIds) > 0: courseIds = config.courseIds.split(',') for courseId in courseIds: if len(config.queryStudentCodes) > 0: studentCodes = config.queryStudentCodes.split(',') for studentCode in studentCodes: querydetail(1, examId, courseId, studentCode) else: querydetail(1, examId, courseId, None) else: if len(config.queryStudentCodes) > 0: studentCodes = config.queryStudentCodes.split(',') for studentCode in studentCodes: querydetail(1, examId, None, studentCode) else: querydetail(1, examId, None, None) print('') print("全部执行完成,失败数:" + str(errCount)) @calctime def querydetail(curpage, examId, courseId, studentCode): print('') global errCount url = "https://" + config.domain + "/api/ecs_oe_admin/exam/record/detail/list" params = {"rootOrgId": config.rootOrgId, "examRecordDataId": None, "hasStranger": None, "courseId": courseId, "courseLevel": None, "examId": examId, "faceSuccessPercentLower": None, "faceSuccessPercentUpper": None, "identityNumber": None, "orgId": None, "studentCode": studentCode, "studentName": None, "isWarn": None, "pageNo": curpage, "pageSize": 500, "startTime": None, "endTime": None, "infoCollector": None, "hasVirtual": None, "ORG_FIND_ALL": True, "examStageId": "", "examType": "ONLINE"} result = requests.post(url, json=params, headers=config.header, verify=False) if result.status_code == 200: contents = result.json()["content"] totalPages = result.json()["totalPages"] totalElements = result.json()["totalElements"] print("---> totalElements=" + str(totalElements) + " totalPages=" + str(totalPages) + " curPage=" + str(curpage) + " examId=" + str(examId) + " courseId=" + str(courseId)) for content in contents: try: solveexamRecord(examId, content) except Exception as e: errCount += 1 print("网络异常,下载失败! " + content["courseCode"] + "_" + content["identityNumber"] + "_" + content["studentName"] + " 失败数:" + str(errCount)) if curpage < totalPages: querydetail(curpage + 1, examId, courseId) else: raise Exception("获取数据失败,请检查配置参数或网络是否正常!") @calctime def findExamRecordDataEntity(examRecordId): url = "https://" + config.domain + "/api/ecs_oe_admin/exam/record/data/findExamRecordDataEntity" params = { "examRecordDataId": examRecordId } result = requests.get(url, params=params, headers=config.header, verify=False) # print(result.json()) if result.status_code == 200: return result.json() else: # print(result.status_code) # print(result.json()) return None @calctime def getExamRecordPaperStruct(examRecordDataId): url = "https://" + config.domain + "/api/ecs_oe_admin/examRecordPaperStruct/getExamRecordPaperStruct" params = { "examRecordDataId": examRecordDataId } result = requests.get(url, params=params, headers=config.header, verify=False) if result.status_code == 200: return result.json() else: return None @calctime def getExamRecordQuestions(examRecordDataId): url = "https://" + config.domain + "/api/ecs_oe_admin/examRecordQuestions/getExamRecordQuestions" params = { "examRecordDataId": examRecordDataId, "withScore": True, } result = requests.get(url, params=params, headers=config.header, verify=False) if result.status_code == 200: return result.json() else: return None @calctime def getQuesitons(examId, courseCode, groupCode, questionId): url = "https://" + config.domain + "/api/ecs_ques/default_question/question" data = {"examId": examId, "courseCode": courseCode, "groupCode": groupCode, "questionId": questionId} result = requests.post(url, json=data, headers=config.header, verify=False) if result.status_code == 200: return result.json() else: return None def solveexamRecord(examId, examRecorddetail): identityNumber = examRecorddetail["identityNumber"] studentName = examRecorddetail["studentName"] examrRecordDataId = examRecorddetail["id"] courseCode = examRecorddetail["courseCode"] courseName = examRecorddetail["courseName"] studentCode = examRecorddetail["studentCode"] if len(config.skipStudentCodes) > 0: # print(studentCode + ' ' + str(config.skipStudentCodes.find(studentCode))) if config.skipStudentCodes.find(studentCode) > -1: print("配置为跳过! " + courseCode + "_" + identityNumber + "_" + studentName + ".pdf") return None record = bs4.BeautifulSoup( open(common.resource_path(os.path.join("template", "template.html")), "r", encoding="utf-8"), features="html.parser") if config.useStudentCodePath == 'true': filepath = config.outputpath + os.sep + str( examId) + os.sep + courseCode + "_" + studentCode + "_" + studentName + ".pdf" else: filepath = config.outputpath + os.sep + str( examId) + os.sep + courseCode + "_" + identityNumber + "_" + studentName + ".pdf" if os.path.exists(filepath): print("已处理,跳过! " + courseCode + "_" + identityNumber + "_" + studentName + ".pdf") return None result = findExamRecordDataEntity(examrRecordDataId) # print(result) groupCode = result["examRecord"]["paperType"] defaultPaper = getExamRecordPaperStruct(examrRecordDataId)["defaultPaper"] papername = defaultPaper["name"] record.select_one("#paperName").string = str(papername) record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(1)").string = str(examrRecordDataId) record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(2)").string = str(studentCode) record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(3)").string = str(studentName) record.select_one("#studentInfoTable > tbody > tr > td:nth-of-type(4)").string = str(courseName) + "(" + str( courseCode) + ")" paperViewTag = record.select_one("#paperView") questionGroupList = defaultPaper["questionGroupList"] quesitonEntites = getExamRecordQuestions(examrRecordDataId)["examQuestionEntities"] main_number = 1 sub_number = 1 for questionGroup in questionGroupList: groupName = questionGroup["groupName"] groupScore = questionGroup["groupScore"] mainQuestionDiv = record.new_tag("div", attrs={"class": "mainQuestionDiv", "data-v-3575fe23": ""}) paperViewTag.append(mainQuestionDiv) groupDiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "font-size: 16px; font-weight: bold;"}) mainQuestionDiv.append(groupDiv) mainQuestionDiv.append(record.new_tag("div", attrs={"data-v-3575fe23": ""})) datadiv = record.new_tag("div", attrs={"data-v-3575fe23": ""}) mainQuestionDiv.append(datadiv) datadiv1 = record.new_tag("div", attrs={"data-v-3575fe23": ""}) datadiv.append(datadiv1) questionWrapperList = questionGroup["questionWrapperList"] groupDiv.string = common.four_to_han(str(main_number)) + "、" + groupName + "(" + str(groupScore) + "分" + ")" for questionWrapper in questionWrapperList: questionId = questionWrapper["questionId"] quesitondetail = getQuesitons(examId, courseCode, groupCode, questionId) main_body = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "display: flex; flex-direction: row;"}) datadiv1.append(main_body) if quesitondetail["masterVersion"]["body"]: main_body_div = record.new_tag("div", attrs={"data-v-3575fe23": ""}) main_body.append(main_body_div) soup = bs4.BeautifulSoup(quesitondetail["masterVersion"]["body"], features="html.parser") main_body_div.append(soup) questionUnitList = quesitondetail["masterVersion"]["questionUnitList"] for questionUnit in questionUnitList: questionType = questionUnit["questionType"] questiondiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "clear:both"}) datadiv1.append(questiondiv) bodydiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "display: flex; flex-direction: row;"}) questiondiv.append(bodydiv) sub_number_div = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"}) sub_number_div.string = str(sub_number) + "、" content_div = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"}) score_span = record.new_tag("span", attrs={"data-v-3575fe23": "", "style": "float:left"}) bodydiv.append(sub_number_div) bodydiv.append(content_div) bodydiv.append(score_span) body = questionUnit["body"] soup = bs4.BeautifulSoup(body, features="html.parser") # content_div.append(str(sub_number)+"、") content_div.append(soup) rightAnswer = questionUnit["rightAnswer"] curRightAnswer = '' if rightAnswer and len(rightAnswer) > 0: curRightAnswer = rightAnswer[0] quesitonEntity = quesitonEntites[sub_number - 1] optionorder = quesitonEntity["optionPermutation"] questionScore = quesitonEntity["questionScore"] studentAnswer = quesitonEntity["studentAnswer"] studentScore = quesitonEntity["studentScore"] questionOptionList = questionUnit["questionOptionList"] score_span.string = "(" + str(questionScore) + "分)" if questionOptionList: option_idex = 0 for option in optionorder: optiondetail = questionOptionList[option] optiondiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "clear:both"}) datadiv1.append(optiondiv) optiondiv1 = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "display: flex; flex-direction: row;"}) optiondiv.append(optiondiv1) optionIndexdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"}) optiondiv1.append(optionIndexdiv) optionContentdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"}) optiondiv1.append(optionContentdiv) optionIndexdiv.string = chr(65 + int(option_idex)) + "、" soup = bs4.BeautifulSoup(optiondetail["body"], features="html.parser") optionContentdiv.append(soup) option_idex = option_idex + 1 answerdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "clear:both"}) datadiv1.append(answerdiv) rightAnswerdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "display: flex; flex-direction: row; color: green; font-weight: bold;"}) rightAnswerdivtitle = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"}) rightAnswerdivcontent = record.new_tag("span", attrs={"data-v-3575fe23": "", "style": "float:left"}) answerdiv.append(rightAnswerdiv) rightAnswerdiv.append(rightAnswerdivtitle) rightAnswerdiv.append(rightAnswerdivcontent) rightAnswerdivtitle.string = "标准答案:" studentAnswerdiv = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "color: blue; font-weight: bold;clear:both"}) answerdiv.append(studentAnswerdiv) studentAnswerdiv.string = "学生答案:" studentAnswercontentspan = record.new_tag("span", attrs={"data-v-3575fe23": ""}) studentAnswerdiv.append(studentAnswercontentspan) if questionType == "SINGLE_CHOICE" or questionType == "MULTIPLE_CHOICE": correctAnswer = quesitonEntity["correctAnswer"] # print(correctAnswer,studentAnswer) rightAnswerdivcontent.append( selectorder(correctAnswer, optionorder)) studentAnswercontentspan.append( selectorder(studentAnswer, optionorder)) elif questionType == "TRUE_OR_FALSE": f = lambda x: "" if not x else "正确" if x == "true" else "错误" # print(f(curRightAnswer)) rightAnswerdivcontent.append(f(curRightAnswer)) studentAnswercontentspan.append(f(studentAnswer)) else: rightAnswerdivcontent.append( bs4.BeautifulSoup(curRightAnswer if curRightAnswer else '', features="html.parser")) studentAnswercontentspan.append( bs4.BeautifulSoup(studentAnswer if studentAnswer else '', features="html.parser")) student_score_div = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "color: red; font-weight: bold;clear:both"}) answerdiv.append(student_score_div) right_score_div_title = record.new_tag("div", attrs={"data-v-3575fe23": "", "style": "float:left"}) right_score_div_title.string = "得分:" student_score_div.append(right_score_div_title) student_score_content_span = record.new_tag("span", attrs={"data-v-3575fe23": ""}) if studentScore is None: student_score_content_span.string = "--分" else: student_score_content_span.string = str(studentScore) + "分" student_score_div.append(student_score_content_span) # print(main_number, " ", sub_number, " ", questionScore, " ", studentScore, # " ", rightAnswer, " ", studentAnswer) sub_number = sub_number + 1 main_number = main_number + 1 with open(common.resource_path(os.path.join("template", "temp.html")), 'w', encoding="utf-8") as fp: fp.write(record.prettify()) if not os.path.exists(config.outputpath + os.sep + str(examId)): os.makedirs(config.outputpath + os.sep + str(examId)) common.convert_to_pdf(common.resource_path(os.path.join("template", "temp.html")), filepath) print("已完成! " + courseCode + "_" + identityNumber + "_" + studentName + ".pdf examrRecordDataId=" + str( examrRecordDataId)) def selectorder(answer, optionpremutation): if answer: answerstr = [] for answerorder in answer: # print(optionpremutation) index = optionpremutation.index(int(answerorder)) answerstr.append(chr(65 + index)) answerstr.sort() return ",".join(answerstr) else: return ""