构思
整体思路
通过API调用获取错题信息,将数据存入数据库(保证可长期查看),通过python+django将数据库数据在前端呈现。
实施思路
1、通过抓包获取到小程序相对应的错题集API信息(url、path、参数、请求方法),分析响应信息,分析获取API之间的关联关系,输出API文档。 2、通过数据关系,搭建数据库结构,创建数据库表。 3、设计方法类: 1)调用API,获取响应数据 2)将响应数据存入数据库 3)后端读取数据库数据,并返回前端界面。 4)前端设计错题以卡片的形式展示错题集。
实施过程
调用API获取响应数据
抓包获取API信息
使用charles进行抓包,因为小程序使用的是HTTPS请求,此处代理需要开启HTTPS代理请求,建议开启全局代理(即计算机代理),其实在开始charles时会默认开启。在此需要设置HTTPS的代理端口。
【问题】 1、抓包小程序需要清理小程序缓存,查询WMPFRuntime文件夹所在位置,删除该文件夹即可。 2、抓包小程序过程中,总提示小程序认证失败,再次登录却提示“设备参数缺失”,此时可以先退出charles,登陆后再打开charles,即可正常获取认证信息。 3、获取的API信息,其中的token,在python设置参数时需要进行url解码,再进行请求。
python发送HTTPS请求
1 def GetExercisebook(): 2 # SQL集 3 4 pmpExerciseManualInsertSQL = "INSERT INTO `mysql_python`.`pmp_exercise_manual` (`id`, `history_id`, `subject`, `name`, `exam_type_id`) VALUES (%s, %s, %s, %s, %s);" 5 pmpManualSubjectInsertSQL = "INSERT INTO `mysql_python`.`pmp_manual_subject` (`manual`, `subject`) VALUES (%s, %s);" 6 pmpSubjectInsertSQL = "INSERT INTO `mysql_python`.`pmp_subject` (`subjectId`, `type_name`, `content`, `opt`, `correct_answer`, `analysis`, `label_text`) VALUES (%s, %s, %s, %s, %s, %s, %s);" 7 8 # token 值(不同设备登陆后需要更新此部分) 9 TOKEN_NEW = '********' 10 11 # 获取问题集---请求参数params 12 VALUE = {"clienttype": "2", 13 "exam_type": "****", 14 "isBusy": "true", 15 "isOver": "false", 16 "loadingTips": "*******", 17 "login_status": "2", 18 "page": "0", 19 "pageSize": "100", 20 "login_status": "2", 21 "token": TOKEN_NEW 22 } 23 url = "https://*******/api/v2/****/****/history/exercise" 24 payload = "" 25 headers = { 26 } 27 print("*********************开始发送请求********************") 28 ResponseProblemBook = requests.request("GET", url, headers=headers, data=payload, params=VALUE) 29 print(ResponseProblemBook.request) 30 ProblemBook = ResponseProblemBook.json() 31 subjectDetailList = ProblemBook['data'] 32 print("*********************获取响应成功********************") 33 34 # 遍历获取习题信息 35 num = 0 36 pmpExerciseManualInsertVal = [] 37 for num in range(len(subjectDetailList)): 38 pmpManualSubjectInsertVal = [] 39 pmpSubjectInsertVal = [] 40 id = subjectDetailList[num]['id'] 41 history_id = subjectDetailList[num]['history_id'] 42 name = subjectDetailList[num]['name'] 43 exam_type_id = subjectDetailList[num]['exam_type_id'] 44 subject = subjectDetailList[num]['subject'] 45 bSubject = qieString(subject) 46 for subjectId in bSubject: 47 pmpManualSubjectInsertResult = (id, subjectId) 48 pmpManualSubjectInsertVal.append(pmpManualSubjectInsertResult) 49 url_2 = "https://*******/api/v2/****/****/" + subjectId + "/analysis" 50 VALUE_2 = {"id": subjectId, 51 "exam_type": "****", 52 "clienttype": "2", 53 "login_status": "2", 54 "token": TOKEN_NEW 55 } 56 response_2 = requests.request("GET", url_2, headers=headers, data=payload, params=VALUE_2) 57 response_b = response_2.json() 58 subjectDetailList_b = response_b['data'] 59 type_name_b = subjectDetailList_b['type_name'] # 题目类型 60 correct_answer_b = subjectDetailList_b['correct_answer'] # 答案 61 content_b = subjectDetailList_b['content'] # 问题 62 analysis_b = subjectDetailList_b['analysis'] # 分析 63 opt_b = subjectDetailList_b['opt'] # 选项 64 label_text_b = subjectDetailList_b['label_text'] # 分类标准 65 pmpSubjectInsertResult = ( 66 subjectId, type_name_b, content_b, opt_b, correct_answer_b, analysis_b, label_text_b) 67 pmpSubjectInsertVal.append(pmpSubjectInsertResult) 68 Save_Mysql(pmpManualSubjectInsertSQL, pmpManualSubjectInsertVal) 69 Save_Mysql(pmpSubjectInsertSQL, pmpSubjectInsertVal) 70 print('获取关联表成功:', pmpManualSubjectInsertVal) 71 pmpExerciseManualInsertResult = (id, history_id, subject, name, exam_type_id) 72 pmpExerciseManualInsertVal.append(pmpExerciseManualInsertResult) 73 # print('获取习题集成功:', name) 74 num = num + 1 75 Save_Mysql(pmpExerciseManualInsertSQL, pmpExerciseManualInsertVal)
将响应值存入数据库
1 # 将题目存入数据库,无返回值 2 def Save_Mysql(sql, val): 3 HOST = 'localhost' 4 PORT = 3306 5 USER = 'root' 6 PASSWORD = 'XF950701.' 7 8 connection = pymysql.connect(host=HOST, port=PORT, user=USER, password=PASSWORD, db='mysql_python', charset='utf8') 9 try: 10 cursor = connection.cursor() 11 12 cursor.executemany(sql, val) 13 connection.commit() 14 print("插入成功数据:", cursor.rowcount) 15 except Exception: 16 print("插入失败") 17 finally: 18 cursor.close() # 关闭游标连接 19 connection.close() 20 21 22 # 读取数据库数据输出表格 23 def qieString(subject): 24 aString = subject 25 bString = re.sub(u"\\[|\\]", '', aString) 26 cString = bString.split(',') 27 return cString
获取数据库数据
1 def GetPnP(sql): 2 HOST = 'localhost' 3 PORT = 3306 4 USER = 'root' 5 PASSWORD = 'XF950701.' 6 7 conn = pymysql.connect(host=HOST, port=PORT, user=USER, password=PASSWORD, 8 db='mysql_python', 9 charset='utf8') 10 # 生成sql语句 利用传入的BankConsentId进行条件查询 11 authorize_sql = sql 12 cursor = conn.cursor() 13 try: 14 cursor.execute(authorize_sql) 15 desc = cursor.description # 获取字段的描述 16 data = [dict(zip([col[0] for col in desc], row)) for row in 17 cursor.fetchall()] 18 except: 19 conn.rollback() 20 cursor.close() 21 conn.close() 22 return data
将数据格式化后返回前端页面
1 def GetExercisebook(request): 2 p1 = "<p>|</p>" 3 from Myapp.Dao.HttpsRequest.getpnp import GetPnP 4 5 authorize_sql = "SELECT Id,subjectId,type_name,content,correct_answer,analysis FROM pmp_subject" 6 data = GetPnP(authorize_sql) 7 context = {"code": 200, "data": data} 8 JsonDupsContext = json.dumps(context) 9 opt_demo = re.sub(p1, '', JsonDupsContext) 10 JsonLoadsContext = json.loads(opt_demo) 11 return render(request, 'Exercisebook.html', JsonLoadsContext) 12 13 14 def GetOpt(request): 15 p1 = "<p>|</p>" 16 from Myapp.Dao.HttpsRequest.getpnp import GetPnP 17 subjectId = request.GET['subjectId'] 18 authorize_sql = "SELECT opt FROM pmp_subject where subjectId = "+subjectId 19 opt =GetPnP(authorize_sql) 20 opt_demo = re.sub(p1, "", opt[0]['opt']) 21 context = json.loads(opt_demo) 22 return JsonResponse(context, safe=False)
前端呈现
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 6 7 <title>Exercisebook</title> 8 <meta charset="UTF-8"> 9 <title>卡片效果</title> 10 <style type="text/css"> 11 .cardBox { 12 width: 200px; 13 box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); 14 text-align: center; 15 float: left; 16 margin-right: 10px; 17 padding: 5px; 18 padding-top: 15px; 19 } 20 21 .headerBox { 22 color: #fff; 23 padding: 10px; 24 font-size: 15px; 25 height: 60px; 26 } 27 28 .bodyBox { 29 padding: 10px; 30 } 31 32 .bodyBox p { 33 margin-left: 5px; 34 } 35 </style> 36 <script> 37 function GetOpt(data) { 38 var subjectId = data; 39 $.get('/GetOpt/',{ 40 'subjectId': subjectId 41 },function (ret){ 42 var a = ""; 43 opt = ret; 44 console.log(opt) 45 for(var i = ret.length -1; i >=0 ; i--) { 46 a = ret[i]['label']+":"+ret[i]['content']+'<br>'+a; 47 document.getElementById(subjectId).innerHTML=a; 48 } 49 } 50 ) 51 } 52 </script> 53 </head> 54 </head> 55 <body> 56 <div style="text-align: center;width: 90%"> 57 <div hidden='1000'> 58 <h1 style="text-align: center">错题集 </h1> 59 </div> 60 61 <div style="text-align: center;width: 100%"> 62 <div style="text-align: center"> 63 {% for List in data %} 64 <div class="cardBox" style="text-align:center;width: 22%;height: 600px"> 65 66 <!--卡片头部标签--> 67 <div class="headerBox" style="background-color: #3c5bc2;height: 40px"> 68 <p> 69 <a title="查看详情" style="cursor: pointer; color:white">第{{ List.Id }}题({{ List.type_name }})</a> 70 </p> 71 </div> 72 <!--题目--> 73 <div class="bodyBox"> 74 <p style="text-align: left">{{ List.content }}</p> 75 </div> 76 <!--选项--> 77 <div class="bodyBox"> 78 <script> 79 window.onload=GetOpt({{ List.subjectId }}); 80 </script> 81 <p id="{{ List.subjectId }}" style="text-align: left"> 82 </p> 83 </div> 84 <!--答案 分析--> 85 <div class="bodyBox"> 86 <p style="text-align: left">{{ List.correct_answer }}</p> 87 <br> 88 <p style="text-align: left">{{ List.analysis }}</p> 89 </div> 90 </div> 91 {% endfor %} 92 </div> 93 </div> 94 </div> 95 96 </body> 97 </html>
声明:本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。