赛事星平台的作答脚本Python实现(适用于刷时间)

发布时间 2023-09-27 17:39:36作者: 小驼*

灵感来源:白嫖

某文理的一次答题竞赛,前一百名有奖品正好缺个蓝牙耳机索性就刷个时间白嫖一波吧.咳咳,正式开始分享咯.

准备工作:

谷歌浏览器以及自带开发者工具

页面分析:

由于此次白嫖活动已经结束,就采用其他竞赛URL进行分析,原理相同.
URL:

https://saishi.cnki.net/MatchIndex/hd6343c8ff-adcf-47c3-aa16-efea48477ddf

image
请求得到如上界面,打开开发者工具进行抓包(根据经验,极有可能是ajax请求),如下:
image
经过分析,返回的数据没有什么价值.
image
继续点击 开始答题个人信息随便填一下,观察抓到的包:
image
这个请求返回了这个竞赛的全部题目以及选项等详细信息,格式为JSON.
看他携带了哪些参数:
image
ExamineePaperGUID:不详
_:明显是一个时间戳,经过后续测试,这个参数可以直接写死也可以用time库获取当前时间戳
接下来尝试答题,看会请求到什么:
image

注意UserAnswer,就是我们刚才提交的答案,多次请求观察参数变化可得到:
ExamineePaperGUID:变化的,不详
ExamineeQuetionGUID:变化的,不详
SectionGUID:变化的,不详
SequenceNumber:代表了题目的序号,从1开始
QuestionType:发现一直是3,其实他代表了题目类型,1是选择,3是填空
QuestionScore:代表了题目的分值
其他的参数不变
这会想起来去刚才请求到的JSON数据里看看有啥有价值的信息吗
image
其实JSON数据里面还有QuestionType以及QuestionScore的值,可以在代码里修改成自动获取
image
json里的这部分代表每个题目的ID值
到此所有的参数分析结束
image
点击提交,发现请求到的返回值为空,携带的参数一个是ExamineePaperGUID另一个是固定参数(多提交几次就可以发现)

验证码绕过

在答题过程中,频率太高会跳出验证码,导致刷题失败.如图:
image
这个不是ajax请求,
image
可以看到只携带了一个随机浮点数,可直接写死
因为采用ddddocr库识别验证码有可能失败所以抓到故意输错时的返回值如下:
image
正确的返回值以及请求链接如下:
image
image
至此,仍然存疑的就是ExamineePaperGUID这个参数,虽然JSON数据里有他,可是请求时也携带了他,通过抓包以及全局搜索并未找到这个参数来自何处,亦或是加密形成,所以无法做到输入账号密码,竞赛链接就全自动答题的功能.
登录时password采用了rsa加密算法,需要js逆向,闲了再探索.

脚本编写:

可以采用第三方题库api形式的,也可以自己观察答案以及题目的变化(所以本脚本只适用于题目固定,答案随机的竞赛,其他的需要自己修改,至于账户登录问题我们可以用cookies直接绕过)
使用时,采用抓包工具抓到ExamineePaperGUID参数输入就行.cookie替换成自己的,data列表存放的是题目答案

完整代码

# -*- coding:utf-8 -*-
import random
import time

import ddddocr
import requests

data = ["第一个答案", "第二个答案"]
ExamineePaperGUID = input("请输入:")
headers = {
    "Accept": "application/json, text/javascript, */*; q=0.01",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN,zh;q=0.9,en-US;q=0.8,en-GB;q=0.7,en;q=0.6",
    "Connection": "keep-alive",
    "Cookie": "你自己的cookie",
    "Host": "saishi.cnki.net",
    "Referer": "https://saishi.cnki.net/exam/ExamRd/Answer/{0}".format(ExamineePaperGUID),
    "Sec-Fetch-Dest": "empty",
    "Sec-Fetch-Mode": "cors",
    "Sec-Fetch-Site": "same-origin",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/106.0.0.0 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest"
}


def getInfo():
    url = "https://saishi.cnki.net/api/ExamineRd/GetExamineePaperForTest"
    k = 0
    params = {
        "examineepaperguid": ExamineePaperGUID,
        "_": str(int(time.time() * 1000))
    }
    text = requests.get(url=url, headers=headers, params=params).json()
    print(text)
    SectionGUID = text["data"]["Sections"][0]["SectionGUID"]
    question_list = []
    option_list = []
    for i in text["data"]["Questions"]:
        question_list.append(i["ExamineeQuetionGUID"])
        option_list.append(i["Option"])
    result = []
    for i in option_list:
        for dic in i:
            if data[k] in str(dic):
                result.append(list(dic.values())[0])
        k = k + 1
    return SectionGUID, question_list, result


def start():
    sec, qu_list, result = getInfo()
    post_url = 'https://saishi.cnki.net/api/ExamineRd/SubmitUserAnswer'
    for i in range(len(qu_list)):
        data = {
            "ExamineeQueID": "0",
            "ExamineeQuetionGUID": qu_list[i],
            "ExamineePaperGUID": ExamineePaperGUID,
            "SectionNumber": "0",
            "SectionGUID": sec,
            "SequenceNumber": str(i + 1),
            "QuestionType": "1",
            "QuestionScore": "2",
            "Question": "",
            "Option": "",
            "IsAnswered": "1",
            "IsHasSign": "0",
            "TiankongAnswerCount": "1",
            "UserAnswer": result[i],
            "Tiankong_Answers_Separator": "#$$#"
        }
        print((qu_list[i], str(i + 1)))
        time.sleep(0.2)
        resopnse = requests.post(url=post_url, data=data, headers=headers).json()
        if resopnse['state'] == 'captcha':
            cap()
        else:
            print(resopnse)


def cap():
    for i in range(5):
        url = "https://saishi.cnki.net/api/ExamCaptchaRd/Get/{0}".format(ExamineePaperGUID)
        params = {
            "_": "0.5594454608679078"
        }
        img_data = requests.get(url=url, headers=headers, params=params).content
        with open('./code.jpg', 'wb') as fp:
            fp.write(img_data)

        ocr = ddddocr.DdddOcr(old=True)
        with open("code.jpg", 'rb') as f:
            image = f.read()
        res = ocr.classification(image)
        v_url = "https://saishi.cnki.net/api/ExamCaptchaRd/Verify/{0}".format(ExamineePaperGUID)
        params1 = {
            "captcha": str(res)
        }
        response1 = requests.get(url=v_url, headers=headers, params=params1).json()
        if response1['state'] == 'success':
            print('验证成功')
            break


def submit(ExamineePaperGUID):
    re_url = "https://saishi.cnki.net/api/ExamineRd/SubmitExaminee"
    data1 = {
        "ExamineePaperGUID": ExamineePaperGUID,
        "SubmitMode": "2"
    }
    requests.post(url=re_url, headers=headers, data=data1)


if __name__ == '__main__':
    start()
    submit(ExamineePaperGUID)
    print("提交结束!!")