autojs之自动答题思路详解

综合之前的知到答题和四史答题,在这里写一些总结,

文章目录

  • 一、总流程
    • 1. 从网上爬取题库,保存文档
    • 2. 读取文档,获取键值对
    • 3. 提取页面题目和选项
    • 4. 键名(题目)匹配,获得键值(答案)
    • 5. 点击答案
    • 6. 其他
  • 总结


一、总流程

  1. 从网上爬取题库,保存文档
  2. 读取文档,获取键值对
  3. 提取页面题目和选项
  4. 键名(题目)匹配,获得键值(答案)
  5. 点击答案
  6. 其他

1. 从网上爬取题库,保存文档

爬取题库,倒也不是什么高大上的东西,之前写的python爬题库,也不过是记录自己的学习结果,实在不会也可以复制粘贴
然后是对题库的处理,主要是对replace的运用,实际上你用文档自带的替换可能更快更简单。

2. 读取文档,获取键值对

先将文档保存到手机上,脚本能访问到的位置即可
参照之前的autojs之自动答题

//读取文档
path="/storage/emulated/0/脚本/行政.js"		
var tiku =files.read(path)
//处理特殊字符
pattern=/[`~!@#$^&*()=|';'“”\\\[\]\.<>\/?~!@#¥……&*()——|【】';:'。,、?\s]/g;
tiku = tiku.replace(pattern,"")  
//转换为键值对
tiku = eval("(" + tiku + ")");
//只有你的题库文档中有地方格式不对,这个eval就会报错
//必须是这样:{"题目":"答案","题目":"答案"}

3. 提取页面题目和选项

使用autojs悬浮窗,分析页面,获得题目和选项的唯一标识

autojs之自动答题思路详解_第1张图片

可能是:text,id,desc;
autojs之自动答题思路详解_第2张图片

//点击答案
click(daan)
//这个答案选项的text属性里就是"我是答案字符串",所以可以直接点击
//四史中就不可以了,下面讲解

也可能需要多种属性确定:
className(“android.view.View”).depth(“8”).drawingOrder(“0”).indexInParent(“2”)

//获取题目
var wenti = className("android.view.View").depth("8").drawingOrder("0").indexInParent("2").findOnce().text()
//多种属性不是每个都必须,只要能确定唯一指向题目或答案字符串即可
//然后也要对获取的题目进行处理,去除所有特殊字符

的就属四史答题了
大家仔细观察这张图片,有没有发现和知到答题有什么不同

autojs之自动答题思路详解_第3张图片

没错,四史答题中把题目和选项都切分成了好多小块,这样就没办法通过上面两个方法获得题目和点击答案了,而且网上竟然找不到和我一样的问题,可是把我难为了好几天,尝试了好多种方法(比如就用其中的一块文字进行匹配,还有通过属性标识进行拼接获得完整的文字,也想过通过截图然后百度识图提取题目和选项,但是因为种种原因,这些方法都不好使),最后采取了比较靠谱的方法:

-对于题目,可以通过提取整个页面的文字,然后根据开头【单/多选题】和结尾【出题:武汉大学】/[题目来源:湘潭/西安交通/上海交通大学],将中间的题目提取出来;

    控件 = className("android.view.View").find();
    题目 = ''
    jj = 0
    for (i = 0; i < 控件.length; i++) {
     
        控件里的文字 = 控件[i].text();
        if (控件里的文字 != "") {
     
            题目 += 控件里的文字;

            if (控件里的文字.indexOf('学】') > -1 || 控件里的文字.indexOf('学]') > -1) {
     
                break
            }
        }
    }

    if (题目.indexOf("题】") != -1) {
      //【单选题】【多选题】
        var index = 题目.indexOf("题】")
        题目 = 题目.substring(index + 2, 题目.length)
    }
    if (题目.indexOf("【出题:武汉大学】") != -1) {
     
        var index = 题目.indexOf("【出题:武汉大学】")
        题目 = 题目.substring(0, index)
    }
    if (题目.indexOf("[题目来源:") != -1) {
         //[题目来源:湘潭大学西安交通大学上海交通大学]
        var index = 题目.indexOf("[题目来源:")
        题目 = 题目.substring(0, index)
    }

    //对获取的题目进行处理,去除所有特殊字符
    pattern = /[`~!@#$^&*()=|{}':;'“”,\\\[\]\.<>\/?~!@#¥……&*()——|{}【】';:""'。,、?\s]/g;
    题目 = 题目.replace(pattern, "")
    log(题目)

-对于选项,用上面的方法能提取出文字,但是!四个选项都连在一起,分不清ABCD!所以采取了新的处理方法:
从上图可以看到选项被切割了,但是它们还在同一个父框里,所以我通过找父控件,然后获得它的孩子孙子控件中的包含文字的控件,再拼接在一起就是选项了。

for (i = 0; i < 4; i++) {
     
            选项[i] = ''
            if (className("RadioButton").depth("24").indexInParent(i).findOnce())
                className("RadioButton").depth("24").indexInParent(i).findOne().children()
                    .forEach(function (child) {
     
                        //log(child.className());
                        if (child.className() == "android.view.View") {
     
                            if (child.text() != "") {
     
                                if (选项[i] != child.text())
                                    选项[i] += child.text()
                                //log(child.text());
                            }
                            else {
     
                                child.children()
                                    .forEach(function (child) {
     
                                        // log(child.className());
                                        if (child.text() != "") {
     
                                            if (选项[i] != child.text())
                                                选项[i] += child.text()
                                            //log("!" + child.text());
                                        }
                                    });
                            }
                        }
                    });
            log(选项[i]);
        }

可以看到套了很多层(2层)判断,那是因为四史答题里面,选项的文字,它可能是儿子里包含文字,也可能是孙子,还可能是曾孙子(我遇到过曾孙子的情况,但是懒得写了就没加判断)。。。我没有很好的办法一下子提取所有的,所以只能挨个判断了,如果有更好的思路,欢迎提出,一起讨论

4. 键名(题目)匹配,获得键值(答案)

还是参见知到答题

/* 
*匹配答案
*   题库中[第i个题目].indexof(题目)>-1,表示匹配到问题
*   返回答案
*/
function 匹配答案(题库, 题目) {
     
    i = 0
    flag = 0
    while (Object.keys(题库)[i]) {
     
        if (Object.keys(题库)[i].indexOf(题目) > -1) {
     

            flag = 1
            var 答案 = 题库[Object.keys(题库)[i]]
            return 答案
        }
        i++;

    }
    if (flag == 0) 提示文本("没有匹配到问题,自行作答,百度搜索") //没有写百度搜索
    return -1
}

5. 点击答案

四史答题和知到答题的不同之前已经说了,所以没办法直接click(daan),
上面获取了选项,存储在 选项[i]
这里通过if (答案.indexOf(选项[j]) > -1),获得的i就是要点击的选项的indexInParent(j)
单选:

随机位置x = className("android.widget.RadioButton").depth("24").indexInParent(j).findOnce().bounds().centerX() + random(0, 100)
随机位置y = className("android.widget.RadioButton").depth("24").indexInParent(j).findOnce().bounds().centerY() + random(0, 30)
click(随机位置x, 随机位置y)

多选:

随机位置x = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerX() + random(0, 100)
随机位置y = className("android.widget.CheckBox").depth(23).indexInParent(j).findOnce().bounds().centerY() + random(0, 30)
click(随机位置x, 随机位置y)

整体框架:

function 点击答案(答案) {
     
    if (答案 == -1) {
     
   	 	if (!多选) {
     
   	 		toast("无匹配,默认点击第2个")
   	 		。。。
        }
        else if (多选) {
     
        	toast("默认全选")
        	。。。
        }
    }
    else {
     
        if (!多选) {
     
        	for (j = 0; j < 4; j++) {
     }
                if (答案.indexOf(选项[j]) > -1) {
     }
        }
        else if (多选) {
     
        	for (j = 0; j < 4; j++) {
     }
                if (答案.indexOf(选项[j]) > -1) {
     }
        }
    }
}

具体参见四史答题

6. 其他

其他的好像也没什么了,想起来再评论补充,对于验证码,ui,多线程,我的处理还不是很好,再学习学习,之后再总结吧


总结

有我没有写到的,可以评论。

感谢点赞,评论,收藏,关注

你可能感兴趣的:(autojs,android)