RPA脚本开发

Autojs自动化办公脚本开发实战

哔哩哔哩:https://www.bilibili.com/video/BV1te411Z78u

1、RPA脚本开发简介

哔哩哔哩:https://space.bilibili.com/472536225

第一部分:私人助理RPA (脚本部分)

第二部分:业务RPA (脚本部分)

Autojs实现

流程化、标准化 => 系统

2、私人助理RPA的原理

  • 什么是私人助理RPA
  • 使用场景:定时执行、指令执行
  • 简单演示

开发步骤:

  1. 把每天要做任务流程化
    1. RPA唤醒
    2. 下发指令(发朋友圈)
    3. RPA返回结果
  2. 把流程标准化
  3. 开发私人助理RPA的框架
  4. 增加功能扩展的方式
  5. 实现7*24小时运行
  6. 调试优化

3、私人助理RPA的框架开发

准备工作:两个微信,登录到不同或者相同的手机上

1、实现收到消息自动唤醒

2、程序结构分析(长时间运行、能够扩展、方便对接云控和群控)

  • main.js (控制器角色)
  • 功能名.js (实现具体功能)
  • common.js (公共函数)

4、实现指令识别功能

1、判断监听的消息是否是 sender 发过来的

let title = notification.getTitle();
log(title);
if(title == sender){
   toast("收到指令");
}

2、获取收到的指令内容

// 获取指令
let instruct = notification.getText();
// 判断指令
if(instruct.indexOf("条]") !== -1){
   instruct =  instruct.split(":")[1].replace(/^\s*|\s*$/g,"");
}

3、判断获取的指令是否是任务指令

if(jumpModel.indexOf(instruct) !== -1){
   // 进行跳转
   notification.click();
   engines.execScriptFile("/sdcard/脚本/"+ instruct +".js");
}

5、相对路径和绝对路径的使用

相对路径(相对于运行文件):path.js、./path.js、../path.js、../../path.js

绝对路径:/path.js 、/sdcard/脚本/path.js

获取脚本运行路径:

files.cwd()

engines.myEngine().cwd()

6、实现对话的功能

1、判断是否来到聊天界面

// 等待进入聊天界面聊天界面
if(!text(sender).findOne(5000)){
   toastLog("===========未进入聊天界面");
   exit();
}
if(!className("android.widget.EditText").findOne(2000)){
   toastLog("===========未找到输入框");
   exit();
}

2、回复消息在呢

setText("在呢");
sleep(1000);
click("发送")
sleep(1000);

3、等待新消息出现

let msgNode = text(flag).find();
let msgY = msgNode.get(msgNode.size() -1).bounds().centerY();
for(let i = 0;i<30;i++){
   msgNode = text(flag).find();
   let msgY2 = msgNode.get(msgNode.size() -1).bounds().centerY();
   // 判断新信息是否出现
   if(msgY2 !== msgY){
       toast("新消息出现");
       break;
  }else{
       sleep(1000);
  }
}
toast("等待超时");

4、获取新消息并进行相应回复

// 判断新消息内容
let chatCollection = id("com.tencent.mm:id/b4b").visibleToUser().find();
let lastChat = chatCollection.get(chatCollection.size() - 1);
let lastChatText = lastChat.text();
switch(lastChatText){
   case "测试":
       setText("已准备好");
       sleep(1000);
       click("发送")
       sleep(1000);
       break;
   case "退出":
       setText("好的");
       sleep(1000);
       click("发送")
       sleep(1000);
       break;
   default:
       setText("抱歉,未找到相应回复");
       sleep(1000);
       click("发送")
       sleep(1000);
}

5、实现循环对话

let loop = true;
while(loop){

}

7、完善优化对话功能

1、封装等待进入聊天界面的函数

// 等待进入聊天界面
function waitChat(sender){
   
   if(!text(sender).findOne(5000)){
       toastLog("===========未进入聊天界面");
       exit();
  }
   if(!className("android.widget.EditText").findOne(2000)){
       toastLog("===========未找到输入框");
       exit();
  }
}

2、封装发送消息的函数

// 发送消息
function sendText(msg){
   setText(msg);
   sleep(1000);
   let sendBtn = text("发送").className("android.widget.Button").findOnce();
   randClick(sendBtn);
   sleep(1000);
}

function randClick(node){
   let x = node.bounds().centerX();
   let y = node.bounds().centerY();
   let randX = x + random(-10,10);
   let randY = y + random(-10,10);
   click(randX,randY);
}

3、封装等待消息出现的函数

// 等待消息出现
function waitMsg(sendMsg,n){
   // 3、等待新消息出现
   let msgNode = text(sendMsg).find();
   let msgY = msgNode.get(msgNode.size() -1).bounds().centerY();
   // 等待N秒
   for(let i = 0;i<n;i++){
       msgNode = text(sendMsg).find();
       let msgY2 = msgNode.get(msgNode.size() -1).bounds().centerY();
       // 判断新信息是否出现
       if(msgY2 !== msgY){
           toast("新消息出现");
           return true;
      }else{
           sleep(1000);
      }
  }

   return false;
}

4、封装获取对话中的最后一条消息的函数

// 获取对话中的最后一条消息
function getLastChat(idSelector){
   // 4、获取新消息并进行相应回复 "com.tencent.mm:id/b4b"
   let chatCollection = id(idSelector).visibleToUser().find();
   let lastChat = chatCollection.get(chatCollection.size() - 1);
   let lastChatText = lastChat.text();
   return lastChatText;
}

8、集成对话功能到RPA框架

1、将功能放到rpa文件夹

2、使用本地存储传递数据

3、只允许一个脚本功能运行

let engineList = engines.all();

log(engineList)

if(engineList.length > 1){
return;
}

4、防止主脚本二次重启 preventRestart(‘main’);

function preventRestart(){
   let engineList = engines.all();
   log(engineList)
   if(engineList.length > 1){
       let engineId = storage.get("engineId");
       log("正在运行的引擎:"+engineId);
       for (let i = 0; i < engineList.length - 1; i++){
           if (engineId !== engineList[i].id){
               engineList[i].forceStop();
               log("停止脚本引擎"+ engineList[i].id)
               sleep(5000);
          }
      }
  }else{
       storage.put("engineId",engineList[0].id);
  }
}

9、实现自动发朋友圈功能

1、设计触发方式:关键词、对话中

2、获取图片和文案

let sendMsg = '请发图片';
sendText(sendMsg);
let loop = true;
while(loop){
   let res = waitContent(sendMsg);
   if(res){
       // 判断新消息内容
       let chatCollection = id("com.tencent.mm:id/b4b").visibleToUser().find();
       let lastChat = chatCollection.get(chatCollection.size() - 1);
       let lastChatText = lastChat.text();
       if(lastChatText == "请发图片"){
           downloadImg();
           sendText(sendMsg);
      }else{
           log(lastChatText);
           switch(lastChatText){
               case "好了":
                   sendMsg = "请发送文案";
                   sendText(sendMsg);
                   loop = 1;
                   break;
               case "退出":
                   sendText("好的");
                   loop = false;
                   break;
               default:
                   if(loop == 1){
                       PYQText = lastChatText;
                       sendText("文案已获取,开始发圈");
                       loop = false;
                  }else{
                       sendMsg = "抱歉,未找到相应回复\n如果图片已发送完毕,请回复 好了";
                       sendText(sendMsg);
                       sendMsg = '请发图片';
                       sendText(sendMsg);
                  }
          }
      }
  }else{
       sendText("等待超时,已退出");
       break;
  }
}

3、执行发朋友圈功能

10、完善优化发朋友圈功能

1、返回桌面函数的封装

deskTop("com.miui.home:id/icon_title");

// 回到桌面
function deskTop(idSelector){
   for(let i = 0;i<10;i++){
       // 判断是否再桌面
       if(id(idSelector).findOnce()){
           break;
      }else{
           back();
           sleep(1000);
      }
  }

   if(!id(idSelector).text("微信").visibleToUser().findOnce()){
       home();
       sleep(1000)
  }
   toastLog('已回到桌面');
}

2、选择图片的解决方案

clearDir("/storage/emulated/999/Pictures/WeiXin/");
clearDir("/storage/emulated/0/Pictures/WeiXin/");

function clearDir(dir){
   var dirPath = dir;

   var arr = files.listDir(dirPath);
   arr.forEach(element => {
       var filePath = files.join(dirPath, element);

       log(files.remove(filePath));
       sleep(100);
  });
   toast('图片清理成功');
}

3、运行结果反馈到发指令者

function sendBack(backText){
   let loop = true;
   while(loop){
       deskTop();
       // 点击微信
       click(395,1399);
       // 查看来到的是微信
       for(let i = 0;i<10;i++){
           if(text('通讯录').findOne(3000)){
               toast("来到首页");
               break;
          }else{
               back();
               sleep(3000);
          }
      }

       // 判断是否来到微信聊天列表界面
       for(let i = 0;i<10;i++){
           if(text("微信").boundsInside(0, 0, device.width, device.height / 2).visibleToUser().findOnce()){
               toast('来到聊天界面');
               break;
          }else{
               click(144,2119);
               sleep(3000);
          }
      }

       if(!text(sender).visibleToUser().findOnce()){
           click(310,165);
           sleep(10);
           click(310,165);
           sleep(2000);
      }

       findAndClick("text('"+sender+"')");

       if(text(sender).visibleToUser().exists() && descStartsWith("切换到").exists()){
           sendText(backText);
           deskTop();
           loop = false;
      }
  }
}

11、集成发朋友圈功能到RPA框架

1、使用main函数触发功能

2、将重复函数集中到common文件

3、引入common模块

12、实现远程更新功能

1、对话式功能

2、自动保存文件到脚本文件夹

let jsPath = "/storage/emulated/0/Download/WeiXin/";
// 点击最后一个.js文件
let jsCollection = textEndsWith(".js").visibleToUser().find();
let lastJs = jsCollection.get(jsCollection.size() - 1);
let fileName = lastJs.text();
randClick(lastJs);
sleep(3000);
// 关闭出现的对话框
for(let i= 0 ;i<2;i++){
   let confirmBtn = text("确定").findOnce();
   if(confirmBtn){
       randClick(confirmBtn);
       sleep(1500);
  }
}

// 点击右上角三个点
let moreNode = desc("更多信息").findOne(2000);
if(moreNode){
   randClick(moreNode);
   sleep(1500);
}

// 点击保存
let saveNode = text("保存").findOne(2000);
if(saveNode){
   upClick(saveNode);
   sleep(3000);
   // 移动文件到脚本文件夹
   files.move(jsPath+fileName, "/sdcard/脚本/" + fileName);
}

back();

function upClick(node) {
   let x = node.bounds().centerX();
   let y = node.bounds().centerY();
   let randX = x + random(-10,10);
   let randY = y - 50;
   click(randX,randY);
}

function randClick(node){
   let x = node.bounds().centerX();
   let y = node.bounds().centerY();
   let randX = x + random(-10,10);
   let randY = y + random(-10,10);
   click(randX,randY);
}

13、完善优化远程更新功能

1、回到桌面

2、循环返回

function loopBack(str){
   for(let i = 0; i < 5;i++){
       if(text(str).visibleToUser().findOnce()){
           return true;
      }else{
           back();
           sleep(2500);
      }
  }

   return false;
}

3、清空js文件

14、集成远程更新功能到RPA框架

1、使用main文件触发功能

2、将重复函数集中到common文件

3、引入common模块

15、实现动态获取指令功能

1、遍历运行目录的js文件

let dir = engines.myEngine().cwd();
let jsFiles = files.listDir(dir, function(name){
   return name.endsWith(".js") && files.isFile(files.join(dir, name));
});
log(jsFiles);

2、将文件名加入数组

jsFiles.forEach(item => {
   if(item !== "main.js" && item !== "common.js"){
       item = item.split(".j")[0];
       arr.push(item);
  }
})

3、封装动态获取指令的函数

function getJs(dir){
   let jsFiles = files.listDir(dir, function(name){
       return name.endsWith(".js") && files.isFile(files.join(dir, name));
  });
   return jsFiles;
}

function getInstruct(jsFiles){
   let arr = [];
   jsFiles.forEach(item => {
       if(item !== "main.js" && item !== "common.js"){
           item = item.split(".j")[0];
           arr.push(item);
      }
  })
   return arr;
}

4、目录更改后则调用此函数

let jsFiles = getJs(engines.myEngine().cwd());
log(getInstruct(jsFiles));

16、实现卸载功能

1、进入对话后的代码结构

2、根据功能名删除文件

17、完善优化卸载功能

1、返回到桌面

18、集成卸载功能到RPA框架

1、使用main文件触发功能

2、将重复函数集中到common文件

3、引入common模块

下载权限
查看
  • 免费下载
    评论并刷新后下载
    登录后下载
  • {{attr.name}}:
您当前的等级为
登录后免费下载登录 小黑屋反思中,不准下载! 评论后刷新页面下载评论 支付以后下载 请先登录 您今天的下载次数(次)用完了,请明天再来 支付积分以后下载立即支付 支付以后下载立即支付 您当前的用户组不允许下载升级会员
您已获得下载权限 您可以每天下载资源次,今日剩余
0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧