// 请勿让日志窗口遮挡屏幕 /** * description 命中评论回复 * @type {string} */ let packageName = 'com.ss.android.ugc.aweme'; var searchContent, replyWords, hitKeywords, everyNumber, total; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量 run(); /** * description 启用设备 */ function run() { //保持设备唤醒 importClass(android.os.PowerManager); device.keepAwake(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP); //保持屏幕唤醒 device.keepScreenOn(); sleep(1000); swipeToPoint(30, 800, 30, 100, 1000); //脚本停止监听 setStopCallback(function (){ insertTrace('', '', '', "脚本结束"); }); //脚本异常停止监听 // setExceptionCallback(function (msg){ // insertTrace('', '', '', "脚本停止"); // }); getECloudData(); //获取任务数据 } /** * description 获取云控参数 * @return {boolean} : 返回是否成功 */ function getECloudData() { let result = false; let hasData = true, value; let data = new Array(); let group = [{ "groupName" : "短视频代运营搜索词", "dataName" : "斗因-视频搜索词" },{ "groupName" : "短视频代运营话术", "dataName" : "斗因-回复评论话术" },{ "groupName" : "短视频代运营命中关键词", "dataName" : "斗因-评论命中关键词" },{ "groupName" : "短视频代运营执行数量", "dataName" : "斗因-评论执行数量" }]; //通过数据组名或数据名称取得数据 for (let i = 0; i < group.length; i++) { data = ecloud.getData(group[i]); if (data[0]) { if (i == 0) { searchContent = value = data[0].content.split("|"); } else if (i == 1) { replyWords = value = data[0].content.split("\n"); } else if (i == 2) { hitKeywords = value = data[0].content.split("|"); } else if (i == 3) { let array = value = data[0].content.split("|"); everyNumber = array[0]; total = array[1]; } if (!value || value.length == 0) { hasData = false; loge('未设置' + group[i].dataName); break; } } else { hasData = false; loge('未获取' + group[i].dataName); break; } } if (hasData) { logi('已获取任务数据,开始执行...'); randomSleep(); result = true; launch(packageName, 6000, 3); //打开抖音 } return result; } /** * description 通过包名启动应用 * @param packageName {string} : 应用包名 * @param delay {number} : 启动后等待时长(毫秒) * @param startNum {number} : 重试次数 * @return {boolean} : 返回是否成功 */ function launch(packageName, delay, startNum) { let result = false; //判断应用的包名是否存在 if (utils.isAppExist(packageName)) { //判断应用是否在前台 if (getRunningPkg() == null) { loge('请开启辅助功能权限'); } else if (getRunningPkg() === packageName) { logi('应用已经在前台'); result = true; search(); //搜索视频 } else { logi('启动应用...'); let alert_selectors = text("允许"); let num = 0; //判断应用是否启动成功 while (num < startNum) { if (getRunningPkg() === packageName) { insertTrace('', '', '', "应用启动"); logi('启动成功'); result = true; search(); //搜索视频 break; } else if (has(alert_selectors)) { //初次打开应用 可能会弹出是否允许打开的弹窗 let node = alert_selectors.getOneNodeInfo(3000); if (node) { node.click(); } } else { utils.openApp(packageName); sleep(delay); num++; } } } alert(); //应用启动后处理弹窗 } else { toast('应用未安装'); } return result; } /** * description 根据关键词搜索视频 * @return {boolean} : 返回是否成功 */ function search() { //定位到首页 execSync(function () { isHome(); }, 1000); let result = false; //寻找搜索按钮并点击 logi('开始搜索...'); let search = descMatch(".*搜索.*").getOneNodeInfo(5000); if (search) { if (search.click()) { randomSleep(); //寻找输入框 输入搜索词 logi('输入搜索内容...'); let input_selectors = clz("android.widget.EditText").getOneNodeInfo(5000);; let keyword = searchContent[random(0, searchContent.length - 1)]; if (input_selectors) { if (input_selectors.inputText(keyword)) { randomSleep(); //点击搜索 if (search.click()) { insertTrace('', '', keyword, "搜索"); randomSleep(); logi('搜索完成'); //进入视频页 let tab_node = clz("android.widget.Button").getNodeInfo(5000); if (tab_node) { for (let i = 0; i < tab_node.length; i++) { if (tab_node[i].text === "视频") { if (tab_node[i].click()) { randomSleep(); //浏览视频 let video_node = depth(20).getOneNodeInfo(5000); //根据深度匹配 logi('浏览视频...'); if (video_node) { if (video_node.click()) { randomSleep(); let nameSelectors = id("com.ss.android.ugc.aweme:id/title").getOneNodeInfo(2000); let postSelectors = id("com.ss.android.ugc.aweme:id/desc").getOneNodeInfo(2000); insertTrace(postSelectors.text, nameSelectors.text, '', "搜索"); result = true; reply(); //回复评论 break; } else { loge('浏览失败'); exit(); } } } } } } } else { loge('搜索失败'); exit(); } } else { loge('输入失败'); exit(); } } } else { loge('未找到搜索按钮'); exit(); } } return result; } /** * description 回复一级评论 */ function reply() { let completedNumber = 0; //已回复总数 var flag = false; while (true) { //寻找评论图标并点击 toast('打开评论...'); let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000); var hasComments = comment_icon.parent().nextSiblings()[0].child(0); if (hasComments.text == "评论" || hasComments.text == 0) { logi('未找到评论'); randomSleep(); swiper(); //下一个视频 // break; }else { if (comment_icon) { if (comment_icon.click()) { var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000); if (result) { randomSleep(); toast('放大评论区'); let btn = desc("放大评论区").visible(true).getOneNodeInfo(3000); if (btn) { if (btn.click()) { flag = true; randomSleep(); var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000); let num = 0 //回复数量 while (flag) { for (var i = 0; i < result.length; i++) { var hasKey = false; if (num < everyNumber) { toast('浏览第' + (i + 1) + '条评论...'); var comments = result[i].text; //评论内容 for (var n = 0; n < hitKeywords.length; n++) { // execSync(function () { if (comments.includes(hitKeywords[n])) { var sub = result[i].nextSiblings()[0]; //评论节点 var t = sub.child(0); var ip = sub.child(1); hasKey = true; toast('第' + (i + 1) + '条评论命中关键词,进行回复...'); randomSleep(); insertCommentsGot(comments, hitKeywords[n], t, ip); if (result[i].click()) { let title = textMatch(".*自己评论.*").getOneNodeInfo(3000); if (title) { logi('当前评论不允许回复'); num++; completedNumber++; randomSleep(); } else { toast('输入回复内容...'); let words = replyWords[random(0, replyWords.length - 1)]; let input_selectors = clz("android.widget.EditText").getOneNodeInfo(50000); if (input_selectors) { if (input_selectors.inputText(words)) { randomSleep(); let send = text("发送").getOneNodeInfo(3000); if (send) { send.click(); num++; completedNumber++; toast('完成回复'); randomSleep(); // break; } } } } } } // }, 1000); } if (i == result.length - 1 && !hasKey) { num++; completedNumber++; toast('当前视频未找到命中评论'); randomSleep(); } } else if (Number(completedNumber) === Number(total)) { toast("任务完成"); shell.stopApp(packageName); //关闭抖音 home(); exit() } else { let btn = desc("缩小评论区").visible(true).getOneNodeInfo(3000); if (btn.click()) { randomSleep(); } flag = false; go_back(1); toast('当前视频回复完成,下一个视频...'); randomSleep(); swiper(); //下一个视频 break break; } } } } } } else { toast('未找到评论'); randomSleep(); go_back(2); swiper(); //下一个视频 // break; } } } } } } /** * description 异步执行线程 处理弹窗 * @return {boolean} : 返回是否成功 */ function alert() { thread.execAsync(function () { logd('启动线程,查找弹窗'); let btnText = new Array( "下次再说", "以后再说", "关闭", "允许", "暂不", "暂时不要", "我知道了", "知道了", "取消", ); while (true) { for (let i = 0; i < btnText.length; i++) { logd('检查弹窗...'); let node = text(btnText[i]).getOneNodeInfo(1000); if (node) { node.click(); toast('弹窗已处理'); } } sleep(4000); } }); return true; } /** * description 定位到首页 * @return {boolean} : 返回是否成功 */ function isHome() { let result = false; while (true) { var home_selectors = text("首页").getOneNodeInfo(3000); //首页按钮 var message_selectors = text("消息").getOneNodeInfo(3000); //消息按钮 //判断是否在首页 if (home_selectors && message_selectors) { var follow_selectors = text("关注"); //关注按钮 var recommend_selectors = text("推荐"); //推荐按钮 if (has(follow_selectors) && has(recommend_selectors)) { toast('已定位首页'); randomSleep(); result = true; break; } else { home_selectors.click(); sleep(3000); } } else { toast('返回首页...'); //返回上一页 go_back(1); } } return result; } /** * description 自定义返回函数 * @param page {number} : 返回页数 */ function go_back(page) { let count = 0; while (count < page) { back(); count++; randomSleep(); } } /** * description 随机暂停时间 */ function randomSleep() { let min = Math.ceil(3); let max = Math.floor(6); let time = (Math.floor(Math.random() * (max - min + 1)) + min) * 1000; sleep(time); } /** * description 插入埋点 * @param unique_id {string} : 用户唯一编号 * @param post_name {string} : 作品名称 * @param nickname {string} : 用户昵称 * @param keyword {string} : 搜索关键词 * @param operate_type {string} : 操作类型 */ function insertTrace(post_name, nickname,keyword, operate_type) { let time = getDate(); var deviceNo = ecloud.getDeviceNo(); //设备编号 var unique_id = deviceNo.slice(3); let add = { "tableNameEn": "trace", "columns": { "device_no" : deviceNo, //设备编号 "operate_time" : time, //操作时间 "platform" : "抖音", //所属平台 "unique_no" : unique_id, //用户唯一编号 "post_name" : post_name, //作品名称 "nickname" : nickname, //用户昵称 "keyword" : keyword, //搜索关键词 "operate_type" : operate_type, //操作类型 "task_id": ecloud.getTaskInfo().taskId, "task_name": ecloud.getTaskInfo().taskName } } ecloud.dynamicAdd(add); } /** * description 插入命中作品评论 * @param content {string} : 线索 * @param got_word {string} : 命中词 * @param comment_datetime {string} : 评论时间 * @param province {string} : 省 */ function insertCommentsGot(content, got_word, comment_datetime,province) { let time = getDate(); let add = { "tableNameEn": "dy_comments_got", "columns": { "task_id" : '', //任务id "task_name" : '', //任务名 "title" : "", //视频标题 "dy_nickname" : '', //抖音昵称 "content" : content, //线索 "tel" : '',//手机号 "got_word" : got_word ,//命中词 "comment_datetime" : comment_datetime, //评论时间 "grab_datetime" : time, //挖掘时间 "province" : province, //省 "task_id": ecloud.getTaskInfo().taskId, "task_name": ecloud.getTaskInfo().taskName } } ecloud.dynamicAdd(add); } /** * description 获取当前时间 * @return {string} : 返回时间 */ function getDate() { let date = new Date(); let sign2 = ":"; let year = date.getFullYear() // 年 let month = date.getMonth() + 1; // 月 let day = date.getDate(); // 日 let hour = date.getHours(); // 时 let minutes = date.getMinutes(); // 分 let seconds = date.getSeconds() //秒 let weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天']; let week = weekArr[date.getDay()]; // 给一位数的数据前面加 “0” if (month >= 1 && month <= 9) { month = "0" + month; } if (day >= 0 && day <= 9) { day = "0" + day; } if (hour >= 0 && hour <= 9) { hour = "0" + hour; } if (minutes >= 0 && minutes <= 9) { minutes = "0" + minutes; } if (seconds >= 0 && seconds <= 9) { seconds = "0" + seconds; } return year + "-" + month + "-" + day + " " + hour + sign2 + minutes + sign2 + seconds; } /** * description 滑动视频 * @return {boolean} : 返回是否成功 */ function swiper(){ let result = false; //设定坐标 适配全分辨率 let x = device.getScreenWidth() * 7 / 10; let y = device.getScreenHeight() * 8 / 10; let x1 = device.getScreenWidth() * 7 / 10; let y1 = device.getScreenHeight() * 1.5 / 10 if (rnd_Swipe(x,y,x1,y1,100,200,200)) { sleep(3000); logd("滑动完成"); result = true; } return result; } /** * description 仿真随机带曲线滑动 */ function rnd_Swipe(qx, qy, zx, zy,time, times,timess) { //qx, qy, zx, zy, time 代表起点x,起点y,终点x,终点y,times,timess =随机时间(times,timess) let time1,xxy,point,dx0,dx1,dx2,dx3,xxyy time1=random(times,timess) xxy = []; point = []; dx0 = { "x": qx, "y": qy } dx1 = { "x": random(qx - 100, qx + 100), "y": random(qy , qy + 50) } dx2 = { "x": random(zx - 100, zx + 100), "y": random(zy , zy + 50), } dx3 = { "x": zx, "y": zy } for (let i = 0; i < 4; i++) { eval("point.push(dx" + i + ")"); } for (let i = 0; i < 1; i += 0.08) { xxyy = [parseInt(bezier_curves(point, i).x), parseInt(bezier_curves(point, i).y)] xxy.push(xxyy); } gesture(xxy,time, time1); return true; } /** * description 贝赛尔曲线 */ function bezier_curves(cp, t) { let cx,bx,ax,cy,by,ay,tSquared,tCubed,result cx = 3.0 * (cp[1].x - cp[0].x); bx = 3.0 * (cp[2].x - cp[1].x) - cx; ax = cp[3].x - cp[0].x - cx - bx; cy = 3.0 * (cp[1].y - cp[0].y); by = 3.0 * (cp[2].y - cp[1].y) - cy; ay = cp[3].y - cp[0].y - cy - by; tSquared = t * t; tCubed = tSquared * t; result = { "x": 0, "y": 0 } result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x; result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y; return result; } /** * description 手势 */ function gesture(swipeList,time,time1) { let touch1 ,touch2,x,i touch1 = [{"action": 0, "x": swipeList[0][0], "y": swipeList[0][1], "pointer": 1, "delay": time}] for (i in swipeList) { ++i; if (i===swipeList.length-2) {break;} touch1.push({"action": 1, "x": swipeList[i][0], "y": swipeList[i][1], "pointer": 1, "delay": time}); } touch1.push({"action": 2, "x": swipeList[swipeList.length-1][0], "y": swipeList[swipeList.length-1][1], "pointer": 1, "delay": time}) x = multiTouch(touch1, null, null, time1); logd('仿真滑动:'+x); sleep(3000); }