• autojs实现自动答题、复诵答案、100%正确率


    前言:

    最近需要在手机APP上完成每日答题任务。经过一番研究,我发现 Autojs+百度OCR文字识别可以实现安卓手机自动答题,由于我本人也是在工作之余初学Autojs,欢迎各位大神在评论区留言分享。

    演示视频:

    开发环境 : autojs pro 8
    APP : 某个学习软件。

    基于autojs实现安卓手机APP自动答题

    需求分析:

    首先,为什么我提出来用百度OCR文字识别技术?
    autojs可以通过Uiselector.text()抓取文本呀?

    这是因为:
    1、我答题的选项是图片。题目是可以抓取下来,但是作答选项,是个图片,而且每天作答的时候,它的位置来回换。
    每天答题的时候,查看选项时我的心情,就像下图的表情包一样,十分复杂, 久久思索,我基本上要看6-10秒,去回答一道题。
    在这里插入图片描述

    2、百度OCR可以根据提交的截图,按照一行一行的结果,返回某段文字在屏幕中的坐标信息。答题选项,例如正确和错误,都是两行,不在同一行,处理起来简单。
    3、答题没有时间限制,后期经过我的测试,答题速度可以实现3秒一题。
    4、autojs可以截图。
    5、每天答的题都是重复的,不用做数据库。题库是固定的97道,连每天的作答顺序都是固定的,只是选项来回变,所以我在程序里把答案都按顺序写好了。

    所以说,如果题库你没搞定,做答的题还有答题时间限制,各位大哥大姐们,就不要花时间看正文了。
    在这里插入图片描述

    正文:

    1、免费申请百度智能云(限新用户,且需实名认证)

    由于要用到百度OCR文字识别提供的API,就需要先申请个百度智能云账号。
    https://login.bce.baidu.com/?account=&redirect=http%3A%2F%2Fconsole.bce.baidu.com%2Fai%2F%3F_%3D1597892791979#/ai/ocr/overview/index

    用任意一款百度的产品、如百度网盘扫一下登录二维码,只要百度网盘实名认证,它这边就数据互通认证过了。

    新用户进去之后,找到领取免费资源,可以领取1000次文字调用。
    然后,选择创建应用。记住API Key 和 Secret Key。
    在这里插入图片描述

    2、制作题库

    1、把97道题写成了一个字符串,以@作为分隔符,把答案字符串转化成数组。

    function ans(){
        var str ="正确@错误@错误@正确@正确@正确@错误@错误@正确@错误@错误@错误@正确@正确@错误@正确@错误@正确@错误@错误@正确@错误@错误@正确@错误@错误@错误@错误@错误@错误@正确@正确@正确@错误@错误@错误@错误@正确@错误@错误@正确@错误@错误@错误@错误@错误@正确@错误@错误@错误@正确@正确@正确@错误@错误@错误@错误@正确@错误@错误@正确@正确@错误@错误@错误@错误@正确@错误@错误@错误@错误@正确@错误@正确@错误@错误@错误@正确@错误@错误@错误@正确@正确@正确@正确@错误@错误@错误@错误@错误@正确@正确@错误@错误@错误@正确@正确";  
        var splitAdd = str.split("@");//97道题,用@分隔成一个个数组
        return splitAdd;//split()函数,有兴趣的搜扫
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    用的时候,直接for循环,调用就行了,如下图:
    在这里插入图片描述

    3、截图与读取

    autojs知识 ,captureScreen()、 images.read()
    用的时候,先写个函数,向手机申请一下截图权限,这样97道题,一道一道自动截图,方便。

    //1、先获取截图
    function  获取截图权限(){
        console.log("正在请求截图");
        if(!requestScreenCapture())
            {
            toast("请求截图失败");//获取截图权限;
            exit();  
            }else{
                console.log("准备答题");
            }
    }
    //2、用编号i保存,方便for循环
    captureScreen("/sdcard/" +i+ ".jpg");//2、截图第i张
    var img = images.read("/sdcard/"+ i +".jpg");//3、读取第i张
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    这里的imges对象,调用结束的时候,一定要记得做recycle()回收,否则容易导致内存泄露。

    4、传图片给百度OCR,并识别返回结果

    传图片,涉及的知识,就图片经过base64编码,传给百度API。
    至于百度为什么愿意帮你文字识别,就涉及到access_token。
    这里我不细说,百度文字识别库里有教程。
    所以,要用到步骤1中的向百度申请的API Key 和 Secret Key。
    如下图,很多人评论说,
    如果autojs 报错误:: TypeError Cannot call method “forEach” of undefined
    是怎么回事。
    在这里插入图片描述
    一是你的API Key 和 Secret Key,没有填写自己的
    二是百度OCR是有1000次等限制,到上限的时候,它会给你传个空字符,建议阅读一下官方文档

    获取百度识图结束后,百度会将识别结果,返回一个json对象:包含文字内容word和所在位置location,这两个变量。

    如果对这一部分内容想深入研究,比如识别发票什么的,建议进入百度智能云官方网站,仔细阅读官方文档。

    //百度智能云 文字识别OCR 接口调用
    function Baidu_ocr(img){
        console.log("调用百度ocr");
        var img64 = images.toBase64(img, "jpg", 100);//1、图片经过base64编码,100代表品质,0~100
        /**** 获取access_token ******/
        var API_Key="";    //
        var Secret_Key="";
        //2、向授权服务地址发送请求
        var getTokenUrl="https://aip.baidubce.com/oauth/2.0/token";
        var token_Res = http.post(getTokenUrl, {
            grant_type: "client_credentials",
            client_id: API_Key,
            client_secret: Secret_Key,
        });
        var access_token=token_Res.body.json().access_token;
    
        /**** 调用ocr ******/
        //3、调用文字识别普通版,新人1000次(含位置信息)
        var ocrUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/general";
        var ocr_Res = http.post(ocrUrl, {
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            access_token: access_token,	
            image: img64,
        });
        var json = ocr_Res.body.json();
        /**** 返回结果 ******/
        return json;//4、返回结果
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    5、识别文字与题库中的答案进行比对,实现找字点击

    由于识别的文字,返回的是数组;
    制作的题库,也是数组。
    通过for循环比对的时候,先要把两个数组,转换成字符串,这样连个字符串比对就容易很多了。
    例如,截图的答案是“A、正确”,我的题库只有“正确”。
    那只要截图中的文字,包含,正确,就行。
    就不用equal()函数了,用indexOf()函数。

    //1、开始遍历题目
    function  判断(){
        for(var i = 0; i <97; i++){
            captureScreen("/sdcard/" +i+ ".jpg");//2、截图第i张
            sleep(20);
            var ansmat = ans();//3、拿出自己制作的题库
            var img = images.read("/sdcard/"+ i +".jpg");//4、读取截图
            sleep(20);
            var res = Baidu_ocr(img);//5、发给百度OCR
            img.recycle();//6、回收发送的图片
            BaiDu_Ocr_Click(ansmat[i],res);//7、根据百度识图结果,进行图片点击
            img.recycle();//8、再回收一次,防止内存泄露
            sleep(50);
            确定点击();
        }
    }
    //7、根据百度识图结果,进行图片点击
    function BaiDu_Ocr_Click(ansmat,res){
        var isClick = false;//7.1、默认否
        var a = res.words_result;//7.2、读取百度返回的结果
            // console.log(a[4].words); //试试读出来是啥题
         a.forEach(function(w){
         //7.3、如果选项包含题库答案,就根据百度OCR返回的结果中提供的left、top参数点击这个坐标。
            if (w.words.indexOf(ansmat)!= -1) {
                // log("此题选"+w.words);  //试试点的是啥题
               isClick = click(w.location.left, w.location.top); //点击指定的文字
                return;
            }
        })
        return isClick;//7.4、返回true,方便下一题
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32

    最终效果

    在手机5G网速的情况下,5分钟,答97道,平均3.1秒一道题。在这里插入图片描述
    其实最占用时间的,就是传图片给百度的过程,图片质量参数越低,好像识别结果返回到手机上,就越快。

     var img64 = images.toBase64(img, "jpg", 50);//1、图片经过base64编码,100代表品质,0~100
    
    • 1

    完整代码

    auto.waitFor(); //监听无障碍服务是否启动
    sleep(2000);
    setScreenMetrics(1080,2340);//设置脚本运行环境的,屏幕宽高
    获取截图权限();
    console.log('前台服务: ' + $settings.isEnabled('foreground_service'))
    $settings.setEnabled('foreground_service', true);
    判断();
    结束答题();
    sleep(3000);
    exit();
    function  获取截图权限(){
        console.log("正在请求截图");
        if(!requestScreenCapture())
            {
            toast("请求截图失败");//获取截图权限;
            exit();  
            }else{
                sleep(200);
                console.log("准备答题");
            }
    }
    function  判断(){
        for(var i = 0; i <105; i++){
            captureScreen("/sdcard/" +i+ ".jpg");//截图第i张
            sleep(20);
            console.log("获取第"+ (i+1) +"题");
            var ansmat = ans();
            var img = images.read("/sdcard/"+ i +".jpg");
            sleep(20);
            var res = Baidu_ocr(img);//调用百度识图OCR的API   
            img.recycle();//回收
            BaiDu_Ocr_Click(ansmat[i],res);
            img.recycle();//回收
            sleep(50);
            确定点击();
        }
    }
    
    function ans(){
        var str ="正确@错误@错误@正确@正确@正确@错误@错误@正确@错误@错误@错误@正确@正确@错误@正确@错误@正确@错误@错误@正确@错误@错误@正确@错误@错误@错误@错误@错误@错误@正确@正确@正确@错误@错误@错误@错误@正确@错误@错误@正确@错误@错误@错误@错误@错误@正确@错误@错误@错误@正确@正确@正确@错误@错误@错误@错误@正确@错误@错误@正确@正确@错误@错误@错误@错误@正确@错误@错误@错误@错误@正确@错误@正确@错误@错误@错误@正确@错误@错误@错误@正确@正确@正确@正确@错误@错误@错误@错误@错误@正确@正确@错误@错误@错误@正确@正确";  
        var splitAdd = str.split("@");
        return splitAdd;
    }
    
    
    function 确定点击(){
        var x = text("确定").findOne(300);
        if(x){
            x.click();
                sleep(10);
            // console.log("完成答题");
        }
        sleep(300);
        var y = text("下一题").findOne(3000);
                if(y){
                    y.click();
                    sleep(20);
                    console.log("答错此题");
                }
    }
    function 结束答题(){
        var x = text("完成").findOne(3000);
        if(x){
            x.click();
            console.log("结束");
            sleep(1000);
            captureScreen("/sdcard/判断题截图.jpg");
            console.log("已截图");
        }
        sleep(3000);
        back();
    }
    //百度智能云 文字识别OCR 接口调用
    function Baidu_ocr(img){
        console.log("调用百度ocr");
        /**** 将图片编码 ******/
        var img64 = images.toBase64(img, "jpg", 100);//转换截屏图片
    
        /**** 获取access_token ******/
        var API_Key="     ";//自己的
        var Secret_Key="  ";//自己的
        //向授权服务地址发送请求
        var getTokenUrl="https://aip.baidubce.com/oauth/2.0/token";
        var token_Res = http.post(getTokenUrl, {
            grant_type: "client_credentials",
            client_id: API_Key,
            client_secret: Secret_Key,
        });
        var access_token=token_Res.body.json().access_token;
    
        /**** 调用ocr ******/
        //文字识别普通版(含位置信息)
        var ocrUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/general";
        var ocr_Res = http.post(ocrUrl, {
            headers: {
                "Content-Type": "application/x-www-form-urlencoded"
            },
            access_token: access_token,	
            image: img64,
        });
        var json = ocr_Res.body.json();
        /**** 返回结果 ******/
        return json;
    }
    function BaiDu_Ocr_Click(ansmat,res){
        var isClick = false;
        var a = res.words_result;
            // console.log(a[4].words);
         a.forEach(function(w){
            if (w.words.indexOf(ansmat)!= -1) {
                // log("此题选"+w.words);
               isClick = click(w.location.left, w.location.top); //点击指定的文字
                return;
            }
        })
        return isClick;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
  • 相关阅读:
    Code For Better 谷歌开发者之声----谷歌云基于TensorFlow高级机器学习
    【C语言】内存泄漏调试方式
    10-大数的基本介绍
    导数求函数最大值和最小值习题
    java面试中的高并发的问题
    vue elementui的select组件实现滑到底部分页请求后端接口
    面试现场!月薪3w+的这些数据挖掘SQL面试题你都掌握了吗? ⛵
    4年软件测试工作经验,跳槽之后面试20余家公司的总结
    win10,WSL的Ubuntu配python3.7手记
    算法通关村第二关-白银挑战反转链表拓展问题
  • 原文地址:https://blog.csdn.net/qq_25953411/article/details/125563910