前言:

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

演示视频:

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


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


需求分析:

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

这是因为:

1、我答题的选项是图片。题目是可以抓取下来,但是作答选项,是个图片,而且每天作答的时候,它的位置来回换。

每天答题的时候,查看选项时我的心情,就像下图的表情包一样,十分复杂, 久久思索,我基本上要看6-10秒,去回答一道题。

android智能手机答案 手机智能答题软件_autojs

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

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

android智能手机答案 手机智能答题软件_autojs_02

正文:

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。

android智能手机答案 手机智能答题软件_android智能手机答案_03

2、制作题库

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

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

用的时候,直接for循环,调用就行了,如下图:

android智能手机答案 手机智能答题软件_android智能手机答案_04

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张

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

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

传图片,涉及的知识,就图片经过base64编码,传给百度API。

至于百度为什么愿意帮你文字识别,就涉及到access_token。

这里我不细说,百度文字识别库里有教程。

所以,要用到步骤1中的向百度申请的API Key 和 Secret Key。

如下图,很多人评论说,

如果autojs 报错误:: TypeError Cannot call method “forEach” of undefined

是怎么回事。

android智能手机答案 手机智能答题软件_android智能手机答案_05


一是你的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、返回结果
}

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,方便下一题
}

最终效果

在手机5G网速的情况下,5分钟,答97道,平均3.1秒一道题。

android智能手机答案 手机智能答题软件_自动答题_06


其实最占用时间的,就是传图片给百度的过程,图片质量参数越低,好像识别结果返回到手机上,就越快。

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

完整代码

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;
}