在好例子网,分享、交流、成长!
您当前所在位置:首页Others 开发实例一般编程问题 → Node.js-基于node的灯塔在线答题机器人.zip

Node.js-基于node的灯塔在线答题机器人.zip

一般编程问题

下载此实例
  • 开发语言:Others
  • 实例大小:1.40M
  • 下载次数:21
  • 浏览次数:539
  • 发布时间:2019-08-17
  • 实例类别:一般编程问题
  • 发 布 人:robot666
  • 文件格式:.zip
  • 所需积分:2
 相关标签:

实例介绍

【实例简介】一键 登录(验证码OCR识别) 更新题库 获取试题 自动答题 交卷

【实例截图】

from clipboard

【核心代码】

#!/usr/bin/env node
'use strict';
/**
 * 控制train_data输出
 */
const {debug, myUrl, baseUrl, mockHeaders, mimUsedTime: MIN_USED_TIME} = require('./config');

//解析命令行参数
let argv = require('yargs')
    .option('i', {
        alias: 'identity',
        demand: false,
        default: 'member',
        describe: '你的身份: member 或 people',
        type: 'string'
    })
    .usage('Usage: sdBobot [options]')//用法格式
    .example('sdBobot -i member', 'Your identity is party member.')
    .help('h')
    .alias('h', 'help')
    .alias('v', 'version')
    .epilog('Create by Jessewo | Copyright 2018')//出现在帮助信息的结尾
    .argv;

const request = require('superagent');
const fs = require('fs');
const log = require('./utils/logUtils');
const dateFormat = require('./utils/dateUtils');
const random = require('./utils/randomUtils');
//登录模块
const login = require('./login');

//控制台键盘输入读取
const readlineSync = require('readline-sync');

const DIVIDER = '----------------------------------------------------------------';

let failureList;

let startTime;

/**
 * mock 点击数据
 * 下一题按钮
 * 左上角(552,804)
 * 右下角(644,832)
 */
function mockHumanBehaviors(totalSubject) {
    let clickTimes = totalSubject - 1;
    let clientXArr = [];
    let clientXArrY = [];
    let maxArr = [];
    let obj = {};
    for (let i = 0; i < clickTimes; i  ) {
        let x = random(552, 644);
        clientXArr.push(x);
        let y = random(804, 832);
        clientXArrY.push(y);

        if (obj[x]) {
            obj[x]  ;
            maxArr.push(obj[clientXArr[i]]);
        } else {
            obj[x] = 1
        }
    }
    maxArr = maxArr.sort(function (x, y) {
        return x - y
    });
    let repeatX = maxArr.length > 0 ? maxArr[maxArr.length - 1] : 0; //重复x 坐标的次数

    return {
        sameNum: repeatX,
        clickX: clientXArr.join(','),
        clickY: clientXArrY.join(',')
    };
}

/**
 * 查询答案
 * @param userId
 * @param subjectInfoList
 * @returns {Promise<any>}
 */
function queryAnswer(userId, subjectInfoList) {
    log.d('答案查询中...');
    return new Promise((resolve, reject) => {
        request
            .post(myUrl   "/sdbeacononline/queryanswer")
            .send({userId, subjectInfoList})
            .then(res => {
                let queryResult = res.body.data;
                log.i(queryResult.queryLog);
                resolve(queryResult);
            })
            .catch(err => {
                log.e(err);
            })
    });
}

/**
 * 更新错题集
 * @param {Iterable} failureList
 */
function updateFailureList(failureList) {
    request
        .post(myUrl   "/sdbeacononline/updatefailurelist")
        .send(failureList)
        .then(res => log.d('错题上传成功!'))
        .catch(err => log.e(err));
}

/**
 * 构建交卷的body
 * @param subject
 * @param queryResult
 * @returns {Promise<any>}
 */
function handleResult(subject, queryResult) {
    return new Promise((resolve, reject) => {
        const {recordId, roundOnlyId, orderId, totalSubject} = subject;
        let {answerList, failureMap} = queryResult;

        //对于查询失败的问题抛给用户
        if (failureMap) {
            log.e(`有${Object.values(failureMap).length}个问题查询失败!\n`);

            for (let key in failureMap) {
                let index = parseInt(key);
                let item = failureMap[key];
                const subjectTitle = item.subjectTitle;
                const subjectType = item.subjectType;
                const optionInfoList = item.optionInfoList;

                log.i(`${index   1}.[${subjectType === '0' ? '单选' : '多选'}] ${subjectTitle}`);
                optionInfoList.forEach(opt => log.i(`${opt.optionType}.${opt.optionTitle}`));

                let inputStr = readlineSync.question('请输入答案(示例: 若单选则输入 A ;若多选则输入 ABC): ').trim().toUpperCase();
                // // Handle the secret text (e.g. password).
                // var favFood = readlineSync.question('What is your favorite food? ', {
                //     hideEchoBack: true // The typed text on screen is hidden by `*` (default).
                // });
                while ((subjectType === '0' && !inputStr.match(/^[A-D]{1}$/g))
                || (subjectType === '1' && !inputStr.match(/^[A-D]{1,4}$/g))) {
                    inputStr = readlineSync.question('输入格式错误, 请重新输入:').trim().toUpperCase();
                }
                let correctedOpts = inputStr.match(/./g).join(',');
                log.w(`您输入的是: ${correctedOpts}\n`);
                //将输入的答案添加到错题集里
                item.answer = correctedOpts;
                for (let i = 0; i < inputStr.length; i  ) {
                    let c = inputStr.charAt(i);
                    optionInfoList.forEach(opt => {
                        if (opt.optionType.toUpperCase() == c) {
                            opt.isRight = '1';
                        } else {
                            opt.isRight = opt.isRight || '0';
                        }
                    });
                }

                //构建手动输入的结果
                let answer = {};
                answer.id = item.id;
                answer.answer = correctedOpts;
                //按照原来的顺序插入元素
                answerList.splice(index, 0, answer);
            }
            failureList = Object.values(failureMap);
        }

        //模拟点击数据
        let {sameNum, clickX, clickY} = mockHumanBehaviors(totalSubject);
        //构建交卷body
        let result = {
            recordId,
            roundOnlyId,
            orderId,
            subjectInfoList: answerList,
            sameNum,
            clickX,
            clickY
        };

        let answer = readlineSync.question(`答题完成, 已耗时 ${getUsedTime()}秒, 是否交卷? (Y/N)`).trim().toUpperCase();
        if (answer === 'Y') {
            let tips = '';
            if (getUsedTime() < MIN_USED_TIME) {
                tips = `(建议大于${20 - Math.ceil(getUsedTime())}秒)`;
            }
            let delay = readlineSync.question(`请输入交卷延时${tips}: `).trim().toUpperCase();
            while (!delay.match(/^[\d] $/g)) {
                delay = readlineSync.question('格式错误,请重新输入:').trim().toUpperCase();
            }
            delay = Math.ceil(delay   getUsedTime() >= MIN_USED_TIME ? delay : MIN_USED_TIME - getUsedTime());
            //倒计时
            let intervalId = setInterval(() => {
                log.w(`${delay--}秒后交卷...`);
                if (delay <= 0) {
                    clearInterval(intervalId);
                    resolve(result)
                }
            }, 1000);
        } else if (answer === 'N') {
            log.d('暂不交卷...');
        } else {
            reject('输入错误, 暂不交卷...');
        }
    });
}

function getUsedTime() {
    return (new Date().getTime() - startTime) / 1000;
}

/**
 * 查询剩余答题次数
 * @param userType
 * @returns {Promise<any>}
 */
function getLeftChance(userType, headers) {
    log.d(JSON.stringify(headers));
    let q = {userType};
    if (userType === 0) q.orgId = 0;
    return new Promise((resolve, reject) => {
        request
            .get(`${baseUrl}/quiz-api/game_info/user_left_chance`)
            .query(q)
            .set(headers)
            .then(res => {
                let {code, msg, success, data} = res.body;
                if (code === 200 && success) {
                    resolve(data);
                } else {
                    reject(`getLeftChance: ${code} ${msg}`);
                }
            })
            .catch(err => log.e(err));
    });
}

/**
 * 查询排名和个人答题情况
 * @param headers
 * @returns {Promise<any>}
 */
function getRankList(headers) {
    log.d(JSON.stringify(headers));
    return new Promise((resolve, reject) => {
        request
            .get(`${baseUrl}/quiz-api/personal_rank/weblist?page=0&gameRoundId=`)
            .set(headers)
            .then(res => {
                let {code, msg, success, data} = res.body;
                if (code === 200 && success) {
                    resolve(data);
                } else {
                    reject(`getRankList: ${code} ${msg}`)
                }
            });

    });
}

/**
 * 获取正式的考试题目
 * POST http://xxjs.dtdjzx.gov.cn/quiz-api/game_info/getGameSubject
 * header(登录校验)
 * user_hash:若群众则为手机号;若党员则
 * system-type:web
 * @returns {Promise<any>}
 */
function getSubjectInfoList() {
    return new Promise((resolve, reject) => {
        log.d(JSON.stringify(mockHeaders));
        request
            .post(`${baseUrl}/quiz-api/game_info/getGameSubject`)
            .set(mockHeaders)
            .then(res => {
                let {code, msg, success, data} = res.body;
                if (code === 200 && success) {
                    //缓存试题
                    if (debug) {
                        let jString = JSON.stringify(data);
                        fs.writeFile(`train_data/subjectInfoList-${dateFormat('yyyyMMdd_HH-mm-ss')}.json`, jString, (err) => {
                            if (err) {
                                log.e(err);
                            } else {
                                log.d('试题缓存ok.');
                            }
                        });
                    }

                    startTime = new Date().getTime();
                    log.d(`开始答题, 共计${data.totalSubject}题.\n`);
                    resolve(data);
                } else {
                    reject(`getSubjectInfoList: ${code} Error ${msg}`);
                }
            })
            .catch(err => log.e(err));
    });
}

/**
 * 交卷
 * POST http://xxjs.dtdjzx.gov.cn/quiz-api/chapter_info/countScore
 *
 * 机器人校验
 * 1. 记录点击[下一题按钮]的坐标
 * 2. 记录重复X坐标的次数
 * @param result
 * @returns {Promise<any>}
 */
function submit(result) {
    return new Promise((resolve, reject) => {
        log.d(JSON.stringify(mockHeaders));
        log.d(JSON.stringify(result));
        request
            .post(`${baseUrl}/quiz-api/chapter_info/countScore`)
            .set(mockHeaders)
            .send(result)
            .then(res => {
                let {code, msg, success, data} = res.body;
                if (code === 200 && success) {
                    log.d(JSON.stringify(data));

                    let {recordId, useTime, totalScore, totalRight, totalWrong, overPercen} = data;
                    let w_tt = useTime.split(':');
                    if (w_tt[0] !== '00') {
                        useTime = w_tt[0]   "小时"   w_tt[1]   "分"   w_tt[2]   "秒";
                    } else if (w_tt[1] !== '00') {
                        useTime = w_tt[1]   "分"   w_tt[2]   "秒";
                    } else {
                        useTime = w_tt[2]   "秒";
                    }
                    log.i(DIVIDER);
                    log.i('交卷成功!');
                    log.i(DIVIDER);
                    log.i(`恭喜您! 超过了全省 ${overPercen} 的参赛者`);
                    log.i(`总分: ${totalScore}, 用时${useTime}`);
                    log.i(`正确: ${totalRight}, 错误: ${totalWrong}`);
                    log.i(DIVIDER);

                    resolve(totalScore);
                } else {
                    reject(`交卷失败! ${code} Error ${msg}`);
                }
            })
            .catch(err => log.e(err));
    });
}

async function printUserInfo(userType, hassh) {
    //查询个人信息的header
    let headers = Object.assign({}, mockHeaders);
    headers['Referer'] = `http://xxjs.dtdjzx.gov.cn/index.html?h=${hassh}`;
    let userInfo = await Promise.all([getLeftChance(userType, headers), getRankList(headers)]);
    let leftChance = userInfo[0];
    let {rankList, selfScore, selfRank, rankme, nowTime} = userInfo[1];
    log.i(DIVIDER);
    if (rankme) {
        let {id, orgName, totalScore, avgScore, avgTime, myRank, participationCount} = rankme;
        log.i(`${id}: ${orgName}.`);
        log.i(DIVIDER);
        log.i(`全省排名  ${myRank}`);
        log.i(`平均用时  ${avgTime}`);
        log.i(`答题次数  ${participationCount}`);
        log.i(`总得分    ${totalScore}`);
        log.i(`平均分    ${avgScore}`);
    } else {
        log.i(`${selfRank}: ${selfScore}.`);
    }
    log.i(DIVIDER);
    log.i(`[${nowTime}]`);
    log.i(DIVIDER);
    log.w(`您今天有${leftChance}次答题机会.`);
    return leftChance > 0;
}

function welcome() {
    return new Promise(resolve => {
        let confirm = readlineSync.question(`欢迎使用灯塔在线答题机器人sdBobot. 
用机器代替人类去做简单重复性的劳动是大势所趋, 人类应该花更多的时间投入到更有价值和意义的事情中去, 比如推进个人成长,家庭幸福,事业进步.
开发此软件的目的仅是为了自用, 以及顺便学习node.js, 因此使用此软件答题造成的一切后果与开发者无关.
同意并继续使用请输入 Y 并回车,不同意请输入 N 后回车.
`).trim().toUpperCase();
        resolve(confirm === 'Y');
    });
}

async function main() {
    try {
        let agree = await welcome();
        if (!agree) return;

        //登录
        let {usetype, hassh, session} = await login(argv.i);
        //更新请求头
        //答题用headers
        mockHeaders['user_hash'] = hassh;
        if (session)
            mockHeaders['Cookie'] = session;

        //查询个人信息
        let allow = await printUserInfo(usetype, hassh);
        if (!allow) {
            log.e('今天答题次数已达上限或者不在答题时间!');
            return;
        }

        //获取试题
        let subject = await getSubjectInfoList();

        //查询答案
        let queryResult = await queryAnswer(hassh, subject.subjectInfoList);

        //请求交卷,交卷延时
        let result = await handleResult(subject, queryResult);

        //交卷
        let score = await submit(result);

        //满分则上传更新题库
        if (score === 100 && failureList && failureList.length > 0) {
            updateFailureList(failureList);
        }

    } catch (e) {
        log.e(e);
    }
}

if (require.main === module)
    main();

标签:

实例下载地址

Node.js-基于node的灯塔在线答题机器人.zip

不能下载?内容有错? 点击这里报错 + 投诉 + 提问

好例子网口号:伸出你的我的手 — 分享

网友评论

发表评论

(您的评论需要经过审核才能显示)

查看所有0条评论>>

小贴士

感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。

  • 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
  • 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
  • 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
  • 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。

关于好例子网

本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明

;
报警