编写脚本

将VSCode连接好手机上的autoX以后,打开”通用脚本框架v1.1.js“,复制一份,改名为“yanghao.js” 下面我们使用**通用脚本框架模版**,来编写一个简单的DY养号脚本。 # 设置包名 因为要操作某音,所以要先在全局变量里,设置程序名和包名 ![image.png](https://cos.easydoc.net/52287695/files/lgqkifv8.png) # 设置测试参数 因为是在调试开发阶段,所以要模拟脚本运行的参数。 这个参数,要从redis数据库里,复制全部参数,并**保存到myTaskInfo**这个全局变量里。 ![image.png](https://cos.easydoc.net/52287695/files/lgqkkiqf.png) 从通用模版的大约135行左右开始,有一大段代码被屏蔽了。 这是一段测试代码。在开发的时候,要解除屏蔽。 正式发布的时候,仍然要屏蔽或者删除掉! 测试区域的代码如下: ```javascript // ////////脚本运行参数示例: myTaskInfo = { "task_id": "1", "module_id": "1", "module_name": "yanghao", "module_group_id": "1", "module_param": { "watch_num": "3", "watch_min": "3", "watch_max": "5", "layuiTreeCheck_1": "1", "layuiTreeCheck_9B2EDAE5239A1B55": "9B2EDAE5239A1B55", "layuiTreeCheck_CE36CD237F859F17": "CE36CD237F859F17" }, "custom_param": { "is_limited_time": "0", "limit_time": "600", "wait_time_min": "1", "wait_time_max": "3", "delay_min": "1", "delay_max": "3" }, "module_url": "http://new-cloud.feiyunjs.cn/components/Module/aweme/yanghao.js", "mode": "1", "start_time": "", "task_source": 0, "state": "1", "imei": "9B2EDAE5239A1B55", "device_number": "1B55", "callback_data": "", "remarks": "", "add_time": "2023-04-21 20:33:42", "update_time": "", "replenish_num": 0, "complete_num": 0 } moduleParam = myTaskInfo.module_param; myCustomParam = myTaskInfo.custom_param; if (moduleParam) { // console.log('用户任务参数:' + JSON.stringify(moduleParam)); for (var item in moduleParam) { myModuleParam[item] = moduleParam[item]; } } // 判断应用是否安装 if (getAppName(myApp.packageName)) { main(); } else { console.error('指定应用并未安装:' + myApp.appName); } ``` 这里我们再来捋一遍创建和下发任务的流程。 首先在后台创建一个脚本任务,将任务信息,保存在redis表里。 被控端从后台取到任务后,就获得了redis的任务数据。 在脚本里,对任务信息json进行解析和重构。 然后再执行脚本的逻辑。 脚本任务完成后,通过api接口,将执行结果回传给redis,即修改redis里的任务信息。 # 编写养号代码 接下来,在core()方法的死循环里,编写核心的养号代码。 我们来写一个简单的例子 ```javascript function core() { let isStop = false; //完成任务后是否停止 let isFail = false //是否失败 let delay = random(Number(myCustomParam.delay_min), Number(myCustomParam.delay_max)); //-------------------------------------------------------------------------------------------------------------------------- let version = common.getPackageVersion(myApp.packageName); log("目标App版本:" + version); // 启动应用 launch(myApp.packageName); sleep(10000); common.clickNodeEx('text', '始终允许|允许', delay); log('应用启动结果:', currentActivity()); log('需浏览作品 ' + myModuleParam.watch_num + ' 个'); while (true) { myApp.activity = currentActivity(); // console.log("页面地址:" + myApp.activity) if (isFail) { common.modifyOneTask(myTaskInfo.task_id, 4, JSON.stringify(myTaskInfo), JSON.stringify(info)); //更新任务 break; //跳出循环 } else if (isStop) { // home(); let data = {}; console.info(data); common.modifyOneTask(myTaskInfo.task_id, 3, JSON.stringify(myTaskInfo), JSON.stringify(data)); //更新任务 break; //跳出循环 }; // !!!这里编写脚本的核心代码 // // 简单示例: // for (let index = 0; index < 100; index++) { // log(index); // sleep(500); // // 当满足设定条件时,停止脚本执行,告诉后台任务成功/失败 // if (index > 50) { // isStop = true; //脚本执行成功 // break; // } // } // 翻页浏览作品 for (ii = 0; ii < Number(myModuleParam.watch_num); ii++) { swipe(random(device.width / 3, device.width / 2), random(device.height * 9 / 10, device.height * 8 / 10), random(device.width / 3, device.width / 2), random(device.height * 1 / 10, device.height * 0.5 / 10), random(500, 1000)); let watchTime = random(Number(myModuleParam.watch_min), Number(myModuleParam.watch_max)); log('浏览第 ' + (ii + 1) + ' 个作品 ' + watchTime + ' 秒'); sleep(watchTime * 1000); }; isStop = true; //脚本执行成功 }; }; ``` 完整的脚本代码如下: ```javascript // 保持脚本运行 var ID = setInterval(() => { }, 1000), myApp = {}, myTaskInfo = {}, myModuleParam = {}, moduleParam = [], myCustomParam = {}, myNode = {}, info = {}; myApp.activityArr = new Array(); //存放页面地址 requiresAutojsVersion(635); //此脚本需要Auto.js版本达到指定版本才能运行 myApp.appName = "抖音"; myApp.packageName = "com.ss.android.ugc.aweme"; //-------------------------------------------------------------------------------------------------------------------------- // 加载外部模块 let modulePath = files.cwd() + '/common.js'; // log(modulePath); let common = {}; if (files.exists(modulePath)) { log('引用公共模块'); common = require(modulePath); // var common = require('common.js'); // log(common) } else { console.error('模块加载失败'); exit(); } //-------------------------------------------------------------------------------------------------------------------------- let appConfig = common.getLocalAppConfig(); let str32 = $crypto.digest(appConfig.app_code_js_download, "MD5"); //AES对称加密key,32位字符串 let key = new $crypto.Key(str32); //这里必须用全局变量,否则会报错,提示找不到key //-------------------------------------------------------------------------------------------------------------------------- /** * @mainEngine 父脚本引擎对象 * @taskInfo "App.Record.GetOneTask"接口返回的任务信息对象 * @Description:监听主脚本消息 */ events.on("prepare", function (mainEngine, taskInfo) { // log("任务参数:" + JSON.stringify(taskInfo)) myApp.mainEngine = mainEngine; myTaskInfo = taskInfo ? taskInfo : {}; moduleParam = taskInfo.module_param; myCustomParam = taskInfo.custom_param; if (moduleParam) { // console.log('用户任务参数:' + JSON.stringify(moduleParam)); for (var item in moduleParam) { myModuleParam[item] = moduleParam[item]; } } // log('任务信息',JSON.stringify(taskInfo)); // log('数据类型2:',typeof (taskInfo),typeof (myModuleParam)); try { if (myTaskInfo.mode != '3') { //更新用户任务 common.modifyOneTask(myTaskInfo.task_id, 2, JSON.stringify(myTaskInfo)); //更新任务(0,锁定;1,待执行;2,执行中;3,成功;4,失败;5,超时;) } if (myCustomParam.is_limited_time === "1" || (Number(myCustomParam.limit_time) > 0 && !myCustomParam.is_limited_time)) { log('任务限时:' + myCustomParam.limit_time + "秒"); // 限时任务,检测任务超时 threads.start(function () { let date1 = new Date(); //开始时间 let date2 = date1.getTime(); //在新线程执行的代码 while (true) { let date3 = new Date(); //结束时间 let date4 = date3.getTime(); if ((date4 - date2) > Number(myCustomParam.limit_time) * 1000) { // 设置超时:防止有的页面,比如广告页,没有明显的标识。会出现阻塞的问题。 log("任务已超时。任务ID:" + myTaskInfo.task_id); common.modifyOneTask(myTaskInfo.task_id, 5, JSON.stringify(myTaskInfo)); //更新任务 break; } else { sleep(10 * 1000); }; }; }); } else { log('任务不限时'); }; // 判断应用是否安装 let name = getAppName(myApp.packageName); if (name != myApp.appName) { console.error('指定应用并未安装:' + myApp.appName); } else { main(); } } catch (err) { // log("捕获到异常--->"); log(err); } finally { // log("不管发生不发生错误,我都会执行--->"); }; // clearInterval(ID); //取消一个由 setInterval() 创建的循环定时任务。 }); //当脚本正常或者异常退出时会触发该事件。 //事件处理中如果有异常抛出,则立即中止exit事件的处理(即使exit事件有多个处理函数)并在控制台和日志中打印该异常 events.on("exit", function () { threads.shutDownAll(); //停止所有线程 while (currentPackage() == myApp.packageName) { back(); // 两次回退,快速结束APP sleep(200); back(); sleep(2000); }; home(); console.hide(); try { //向主脚本发送一个事件,该事件可以在它的events模块监听到并在脚本主线程执行事件处理。 myApp.mainEngine.emit("control", "完成"); } catch (error) { } }); //-------------------------------------------------------------------------------------------------------------------------- // // ////////脚本运行参数示例: // myTaskInfo = { // "task_id": "1", // "module_id": "1", // "module_name": "yanghao", // "module_group_id": "1", // "module_param": { // "watch_num": "3", // "watch_min": "3", // "watch_max": "5", // "layuiTreeCheck_1": "1", // "layuiTreeCheck_9B2EDAE5239A1B55": "9B2EDAE5239A1B55", // "layuiTreeCheck_CE36CD237F859F17": "CE36CD237F859F17" // }, // "custom_param": { // "is_limited_time": "0", // "limit_time": "600", // "wait_time_min": "1", // "wait_time_max": "3", // "delay_min": "1", // "delay_max": "3" // }, // "module_url": "http://new-cloud.feiyunjs.cn/components/Module/aweme/yanghao.js", // "mode": "1", // "start_time": "", // "task_source": 0, // "state": "1", // "imei": "9B2EDAE5239A1B55", // "device_number": "1B55", // "callback_data": "", // "remarks": "", // "add_time": "2023-04-21 20:33:42", // "update_time": "", // "replenish_num": 0, // "complete_num": 0 // } // moduleParam = myTaskInfo.module_param; // myCustomParam = myTaskInfo.custom_param; // if (moduleParam) { // // console.log('用户任务参数:' + JSON.stringify(moduleParam)); // for (var item in moduleParam) { // myModuleParam[item] = moduleParam[item]; // } // } // // 判断应用是否安装 // if (getAppName(myApp.packageName)) { // main(); // } else { // console.error('指定应用并未安装:' + myApp.appName); // } //-------------------------------------------------------------------------------------------------------------------------- function main() { console.show(); //------------------------------------------------------------ // log("脚本参数:" + JSON.stringify(myModuleParam)) log(">>> 开始执行:" + myTaskInfo.module_name); log("任务ID:" + myTaskInfo.task_id); home(); core(); log("任务ID:" + myTaskInfo.task_id); log(">>> 任务完成:" + myTaskInfo.module_name); exit(); //激活退出事件 }; function core() { let isStop = false; //完成任务后是否停止 let isFail = false //是否失败 let delay = random(Number(myCustomParam.delay_min), Number(myCustomParam.delay_max)); //-------------------------------------------------------------------------------------------------------------------------- let version = common.getPackageVersion(myApp.packageName); log("目标App版本:" + version); // 启动应用 launch(myApp.packageName); sleep(10000); common.clickNodeEx('text', '始终允许|允许', delay); log('应用启动结果:', currentActivity()); log('需浏览作品 ' + myModuleParam.watch_num + ' 个'); while (true) { myApp.activity = currentActivity(); // console.log("页面地址:" + myApp.activity) if (isFail) { common.modifyOneTask(myTaskInfo.task_id, 4, JSON.stringify(myTaskInfo), JSON.stringify(info)); //更新任务 break; //跳出循环 } else if (isStop) { // home(); // 任务执行成功后,将任务结果回传给服务器 let data = {}; data.result = '共浏览 ' + myModuleParam.watch_num + ' 个'; console.info(data); common.modifyOneTask(myTaskInfo.task_id, 3, JSON.stringify(myTaskInfo), JSON.stringify(data)); //更新任务 break; //跳出循环 }; // !!!这里编写脚本的核心代码 // // 简单示例: // for (let index = 0; index < 100; index++) { // log(index); // sleep(500); // // 当满足设定条件时,停止脚本执行,告诉后台任务成功/失败 // if (index > 50) { // isStop = true; //脚本执行成功 // break; // } // } // 翻页浏览作品 for (ii = 0; ii < Number(myModuleParam.watch_num); ii++) { swipe(random(device.width / 3, device.width / 2), random(device.height * 9 / 10, device.height * 8 / 10), random(device.width / 3, device.width / 2), random(device.height * 1 / 10, device.height * 0.5 / 10), random(500, 1000)); let watchTime = random(Number(myModuleParam.watch_min), Number(myModuleParam.watch_max)); log('浏览第 ' + (ii + 1) + ' 个作品 ' + watchTime + ' 秒'); sleep(watchTime * 1000); }; isStop = true; //脚本执行成功 }; }; ``` 调试运行,日志如下 ```vb 22:00:39.618/V: 开始运行[[remote]yanghao.js] 22:00:39.633/D: 引用公共模块 22:00:39.706/D: >>> 开始执行:yanghao 22:00:39.713/D: 任务ID:1 22:00:39.722/D: 目标App版本:24.7.0 22:00:51.243/D: 应用启动结果: com.ss.android.ugc.aweme.main.MainActivity 22:00:51.245/D: 需浏览作品 3 个 22:00:51.782/D: 浏览第 1 个作品 4 秒 22:00:56.456/D: 浏览第 2 个作品 5 秒 22:01:01.972/D: 浏览第 3 个作品 4 秒 22:01:05.977/I: {} 22:01:06.180/D: 任务ID:1 22:01:06.183/D: >>> 任务完成:yanghao ``` # 上传脚本 脚本编写完成后,先==屏蔽测试区的代码==。 然后上传到服务器。 ![image.png](https://cos.easydoc.net/52287695/files/lgqmkhic.png) 上传以后,进入脚本编辑页面,点击右侧的访问按钮,测试一下脚本是否已经更新。 ![image.png](https://cos.easydoc.net/52287695/files/lgqmndza.png) 如果没有更新,可清理一下浏览器的缓存。 如果脚本中的中文在浏览者中显示乱码,要在VS中看一下文件的编码是否为UTF8,只要是这个编码就可以。 ![image.png](https://cos.easydoc.net/52287695/files/lgqmny0n.png) # 脚本安全 为了防止脚本被别有用心的人获取到,你可以使用一些JavaScript加密工具,对编写好的js脚本进行加密。 需要注意的是,有的加密工具,加密后autojs是无法读取和执行的。 这一块请自行测试和解决。