7 files deleted
5 files added
New file |
| | |
| | | // 对命中评论进行回复, 私信, 点赞操作 |
| | | // 请勿让日志窗口遮挡设备屏幕 |
| | | |
| | | let packageName = 'com.ss.android.ugc.aweme'; //抖音包名 |
| | | |
| | | let searchContent, replyWords, messageWords, hitKeywords, everyNumber, total; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量 |
| | | |
| | | getECloudData(); //获取任务数据 |
| | | |
| | | |
| | | /** |
| | | * description 获取云控参数 |
| | | * @return {boolean} : 返回是否成功 |
| | | */ |
| | | function getECloudData() { |
| | | let result = false, data, hasData = true, value; |
| | | //通过数据组名或数据名称取得数据 |
| | | let group = [{ |
| | | "groupName" : "短视频代运营搜索词", |
| | | "dataName" : "斗因-视频搜索词" |
| | | },{ |
| | | "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]; |
| | | } else if (i == 4) { |
| | | messageWords = value = data[0].content.split("\n"); |
| | | } |
| | | 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 { |
| | | loge('应用未安装'); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * description 根据关键词搜索视频 |
| | | * @return {boolean} : 返回是否成功 |
| | | */ |
| | | function search() { |
| | | //定位到首页 |
| | | execSync(function () { |
| | | isHome(); |
| | | }, 1000); |
| | | let result = false; |
| | | //寻找搜索按钮并点击 |
| | | toast('开始搜索...'); |
| | | let search = descMatch(".*搜索.*").getOneNodeInfo(5000); |
| | | if (search) { |
| | | if (search.click()) { |
| | | randomSleep(); |
| | | //寻找输入框 输入搜索词 |
| | | toast('输入搜索内容...'); |
| | | 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(); |
| | | toast('搜索完成'); |
| | | //进入视频页 |
| | | 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); //根据深度匹配 |
| | | toast('浏览视频...'); |
| | | 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 { |
| | | toast('浏览失败'); |
| | | exit(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | toast('搜索失败'); |
| | | exit(); |
| | | } |
| | | |
| | | } else { |
| | | toast('输入失败'); |
| | | exit(); |
| | | } |
| | | } |
| | | } else { |
| | | toast('未找到搜索按钮'); |
| | | exit(); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * description 回复一级评论 |
| | | * @param p {number} : 私信概率 |
| | | * @param everyNumber {number} : 单个视频回复数量 |
| | | * @param total {number} : 总回复数量 |
| | | */ |
| | | function reply() { |
| | | let completedNumber = 0; //已回复总数 |
| | | var flag = false; |
| | | while (true) { |
| | | //寻找评论图标并点击 |
| | | toast('打开评论...'); |
| | | let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000); |
| | | 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()) { |
| | | 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 //操作类型 |
| | | } |
| | | } |
| | | 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 //省 |
| | | } |
| | | } |
| | | 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); |
| | | } |
New file |
| | |
| | | /** |
| | | * 指定用户私信 |
| | | * |
| | | */ |
| | | let packageName = 'com.ss.android.ugc.aweme'; |
| | | var searchUserIds, replyWords; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量 |
| | | getECloudData(); //获取用户ids |
| | | /** |
| | | * description 获取云控参数 |
| | | * @return {boolean} : 返回是否成功 |
| | | */ |
| | | function getECloudData() { |
| | | |
| | | let result = false; |
| | | let hasData = true, value; |
| | | let data = new Array(); |
| | | let group = [{ |
| | | "groupName": "短视频代运营用户ids", |
| | | "dataName": "斗因-大数据用户id" |
| | | }, { |
| | | "groupName": "短视频代运营话术", |
| | | "dataName": "斗因-回复评论话术" |
| | | }]; |
| | | //通过数据组名或数据名称取得数据 |
| | | for (let i = 0; i < group.length; i++) { |
| | | data = ecloud.getData(group[i]); |
| | | if (data[0]) { |
| | | if (i == 0) { |
| | | searchUserIds = value = data[0].content.split("\n"); |
| | | } else if (i == 1) { |
| | | replyWords = value = data[0].content.split("\n"); |
| | | } |
| | | if (!value || value.length == 0) { |
| | | hasData = false; |
| | | toast('未设置' + group[i].dataName); |
| | | break; |
| | | } |
| | | } else { |
| | | hasData = false; |
| | | toast('未获取' + group[i].dataName); |
| | | break; |
| | | } |
| | | } |
| | | if (hasData) { |
| | | toast('已获取任务数据,开始执行...'); |
| | | randomSleep(); |
| | | result = true; |
| | | launch(packageName, 6000, 3); //打开抖音 |
| | | // reply(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | sendMessage(); |
| | | |
| | | /** |
| | | * 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) { |
| | | toast('请开启辅助功能权限'); |
| | | exit(); |
| | | } else if (getRunningPkg() === packageName) { |
| | | logd('应用已经在前台'); |
| | | result = true; |
| | | } else { |
| | | logd('启动应用...'); |
| | | let alert_selectors = text("允许"); |
| | | let num = 0; |
| | | //判断应用是否启动成功 |
| | | while (num < startNum) { |
| | | if (getRunningPkg() === packageName) { |
| | | logd('启动成功'); |
| | | result = true; |
| | | break; |
| | | } else if (has(alert_selectors)) { |
| | | //初次打开应用 可能会弹出是否允许打开的弹窗 |
| | | let node = alert_selectors.getOneNodeInfo(1000); |
| | | if (node) { |
| | | node.click(); |
| | | } |
| | | } else { |
| | | utils.openApp(packageName); |
| | | sleep(delay); |
| | | num++; |
| | | } |
| | | } |
| | | } |
| | | alert(); //应用启动后处理弹窗 |
| | | operaLog(1, null); |
| | | } else { |
| | | toast('应用未安装'); |
| | | exit(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * 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); |
| | | } |
| | | |
| | | function sendMessage() { |
| | | let result = false; |
| | | //定位到首页 |
| | | // thread.execSync(function () { |
| | | // isHome(); |
| | | // }, 1000); |
| | | let search = descMatch(".*搜索.*").getOneNodeInfo(1000); |
| | | //寻找搜索出现并点击 |
| | | if (search.click()) { |
| | | sleep(3000); |
| | | let input_selectors = clz("android.widget.EditText"); |
| | | let userId = searchUserIds[random(0, searchUserIds.length - 1)]; |
| | | //寻找输入框 输入关键词 |
| | | if (inputText(input_selectors, userId)) { |
| | | sleep(3000); |
| | | //开始搜索 |
| | | if (search.click()) { |
| | | operaLog(2, userId); |
| | | sleep(5000); |
| | | //打开用户页 进入用户列表 |
| | | let tab_node = clz("android.widget.Button").getNodeInfo(1000); |
| | | for (let i = 0; i < tab_node.length; i++) { |
| | | if (tab_node[i].text === "用户") { |
| | | tab_node[i].click(); |
| | | sleep(2000); |
| | | let selector = clz("com.lynx.tasm.behavior.ui.LynxFlattenUI").getOneNodeInfo(1000); |
| | | if (selector.click()) { |
| | | operaLog(3, null); |
| | | // 进入用户主页 |
| | | let words = replyWords[random(0, replyWords.length - 1)]; |
| | | send(words); |
| | | operaLog(6, null) |
| | | } else { |
| | | logd("进入用户主页失败"); |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | loge('搜索失败'); |
| | | exit(); |
| | | } |
| | | } else { |
| | | loge('输入失败'); |
| | | exit(); |
| | | } |
| | | } else { |
| | | loge('未找到搜索按钮'); |
| | | exit(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * description 发私信消息 |
| | | * @param words 私信话术 私信时随机抽取 |
| | | * @return {boolean} : 返回是否成功 |
| | | */ |
| | | function send(words) { |
| | | let result = false; |
| | | let follow = text("关注"); |
| | | let title = text("账号已经注销").getOneNodeInfo(1000); |
| | | //判断是否关注用户 |
| | | let follow_btn = getNodeInfo(follow, 1000); |
| | | if (follow_btn[1]) { |
| | | follow_btn[1].click(); |
| | | operaLog(4, null); |
| | | logd('关注用户'); |
| | | sleep(4000); |
| | | //判断私密账户 |
| | | let private = textMatch(".*私密账号.*").getOneNodeInfo(1000); |
| | | let okArr = new Array( |
| | | "取消", |
| | | "知道了", |
| | | ); |
| | | if (private) { |
| | | for (let i = 0; i < okArr.length; i++) { |
| | | let ok = text(okArr[i]).getOneNodeInfo(1000); |
| | | ok.click(); |
| | | sleep(3000); |
| | | return result; |
| | | } |
| | | } |
| | | } |
| | | let message_btn = text("私信").getOneNodeInfo(1000); |
| | | //判断是否注销 |
| | | if (title) { |
| | | result = false; |
| | | } else if (message_btn.click()) { |
| | | logd('进入私信'); |
| | | sleep(4000); |
| | | let input_selectors = clz("android.widget.EditText"); |
| | | //寻找输入框 输入话术 |
| | | if (inputText(input_selectors, words)) { |
| | | sleep(4000); |
| | | let send_btn = desc("发送").getOneNodeInfo(1000); |
| | | if (send_btn.click()) { |
| | | sleep(4000); |
| | | logd("私信成功"); |
| | | operaLog(5, words); |
| | | result = true; |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | /** |
| | | * description 自定义返回函数 |
| | | * @param page {number} : 返回页数 |
| | | */ |
| | | function go_back(page) { |
| | | let count = 0; |
| | | while (count < page) { |
| | | back(); |
| | | count++; |
| | | sleep(3000); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 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(); |
| | | logd('弹窗已处理'); |
| | | } |
| | | } |
| | | sleep(3000); |
| | | } |
| | | }); |
| | | return true; |
| | | } |
| | | |
| | | /** |
| | | * 记录埋点数据 |
| | | */ |
| | | function operaLog(num, words) { |
| | | let paltform = ''; |
| | | let operateType = ''; |
| | | let uniqueNo = ''; |
| | | if (num === 1) { |
| | | operateType = '应用启动' |
| | | } else if (num === 2) { |
| | | operateType = '搜索' |
| | | } else if (num === 3) { |
| | | operateType = '浏览主页' |
| | | } else if (num === 4) { |
| | | operateType = '关注用户' |
| | | } else if (num === 5) { |
| | | operateType = '私信' |
| | | } else if (num === 6) { |
| | | operateType = '脚本运行结束' |
| | | } |
| | | if ('com.ss.android.ugc.aweme'.equals(packageName)) { |
| | | // 斗音 |
| | | paltform = '抖音' |
| | | uniqueNo = ecloud.getDeviceNo().substring(3) |
| | | } else if ('小红书'.equals(packageName)) { |
| | | // 小红书 |
| | | paltform = '小红书' |
| | | uniqueNo = ecloud.getDeviceNo().substring(4) |
| | | } else if ('快手'.equals(packageName)) { |
| | | // 快手 |
| | | paltform = '快手' |
| | | uniqueNo = ecloud.getDeviceNo().substring(3) |
| | | } |
| | | let add = { |
| | | "tableNameEn": "trace", |
| | | "columns": { |
| | | "device_no": ecloud.getDeviceNo(), |
| | | "platform": paltform, |
| | | "unique_no": uniqueNo, |
| | | "post_name": '', |
| | | "nickname": '', |
| | | "keyword": words, |
| | | "operate_type": operateType, |
| | | "task_id": ecloud.getTaskInfo().taskId, |
| | | "task_name": ecloud.getTaskInfo().taskName, |
| | | } |
| | | } |
| | | ecloud.dynamicAdd(add) |
| | | logd("getMessage 数据保存成功"); |
| | | } |
New file |
| | |
| | | /** |
| | | * description 进入消息模块 |
| | | */ |
| | | let packageName = 'com.ss.android.ugc.aweme'; |
| | | |
| | | execSync(function () { |
| | | launch(packageName, 5000, 2); //打开抖音 |
| | | }, 1000); |
| | | |
| | | toMessage(packageName); |
| | | |
| | | /** |
| | | * 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) { |
| | | toast('请开启辅助功能权限'); |
| | | exit(); |
| | | } else if (getRunningPkg() === packageName) { |
| | | logd('应用已经在前台'); |
| | | result = true; |
| | | } else { |
| | | logd('启动应用...'); |
| | | let alert_selectors = text("允许"); |
| | | let num = 0; |
| | | //判断应用是否启动成功 |
| | | while (num < startNum) { |
| | | if (getRunningPkg() === packageName) { |
| | | logd('启动成功'); |
| | | result = true; |
| | | break; |
| | | } else if (has(alert_selectors)) { |
| | | //初次打开应用 可能会弹出是否允许打开的弹窗 |
| | | let node = alert_selectors.getOneNodeInfo(1000); |
| | | if (node) { |
| | | node.click(); |
| | | } |
| | | } else { |
| | | utils.openApp(packageName); |
| | | sleep(delay); |
| | | num++; |
| | | } |
| | | } |
| | | } |
| | | alert(); //应用启动后处理弹窗 |
| | | operaLog(1); |
| | | } else { |
| | | toast('应用未安装'); |
| | | exit(); |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | function toMessage(packageName) { |
| | | let message_icon = text("消息").getOneNodeInfo(1000); |
| | | //寻找消息图标并点击 |
| | | if (message_icon.click()) { |
| | | operaLog(2); |
| | | sleep(2000); |
| | | let interact_message = text("互动消息").getOneNodeInfo(1000) |
| | | //寻找互动消息图标并点击 |
| | | if (interact_message.click()) { |
| | | operaLog(3) |
| | | sleep(2000); |
| | | logd('互动消息列表...'); |
| | | let grabRequestList = []; |
| | | var node = clz("androidx.recyclerview.widget.RecyclerView").getOneNodeInfo(2000); |
| | | var result = node.allChildren(); |
| | | logd("================"+JSON.stringify(result)); |
| | | if (result != null) { |
| | | for (let i = 0; i < result.length; i++) { |
| | | let value = result[i]; |
| | | let desc = value.desc; |
| | | if (desc == '' || desc == null || desc == 'undefined' || desc == undefined) { |
| | | break; |
| | | } |
| | | if (!value.desc.includes("主页访客")) { |
| | | let grabRequest = { |
| | | nickname: '', |
| | | relation: '', |
| | | comment: '', |
| | | commentTime: '' |
| | | } |
| | | let split = value.desc.split(","); |
| | | if (split.length >= 3) { |
| | | let parts = split[1].trim().split(" "); |
| | | let lastPart = parts.pop(); |
| | | let time = handleTime(lastPart); |
| | | let nicknameAndRelation = split[0].split(","); |
| | | grabRequest.nickname = nicknameAndRelation[0].trim(); |
| | | let relationArr = new Array(["朋友", "作者", "粉丝", "你的关注", "在线"]) |
| | | let relation = ''; |
| | | for (let j = 0; j < relationArr.length; j++) { |
| | | if (!nicknameAndRelation[1].trim().includes(relationArr[i])) { |
| | | relation = '路人' |
| | | } else { |
| | | relation = nicknameAndRelation[1].trim(); |
| | | } |
| | | } |
| | | grabRequest.relation = relation; |
| | | grabRequest.comment = handleComment(split[1].trim(), lastPart); |
| | | grabRequest.commentTime = time; |
| | | grabRequestList.push(grabRequest); |
| | | } else if (split.length === 2) { |
| | | let parts = split[0].trim().split(" "); |
| | | let lastPart = parts.pop(); |
| | | let time = handleTime(lastPart); |
| | | grabRequest.nickname = split[0].trim().split(",")[0]; |
| | | grabRequest.relation = '路人'; |
| | | grabRequest.comment = handleComment(split[0].trim(), lastPart); |
| | | grabRequest.commentTime = time; |
| | | grabRequestList.push(grabRequest); |
| | | } |
| | | } |
| | | } |
| | | save(grabRequestList, packageName); |
| | | logd("数据添加成功!"); |
| | | operaLog(4) |
| | | }else { |
| | | logd("暂无互动消息"); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | function handleComment(comment, lastPart) { |
| | | return comment.substring(0, comment.length - lastPart.length) |
| | | } |
| | | |
| | | function handleTime(lastPart) { |
| | | let time = ''; |
| | | if (lastPart.includes("刚刚") || lastPart.includes("分钟前") || lastPart.includes("小时前")) { |
| | | // 当天 |
| | | time = formatDate(getCurrentDate()); |
| | | } else if (lastPart.includes("昨天")) { |
| | | // 昨天 |
| | | time = formatDate(getDateBeforeDays(getCurrentDate(), 1)); |
| | | } else if (lastPart.includes("天前")) { |
| | | // 几天前 |
| | | var array = lastPart.split("天前"); |
| | | time = formatDate(getDateBeforeDays(getCurrentDate(), parseInt(array[0], 10))); |
| | | } else if (lastPart.split("-").length === 2) { |
| | | // 月-日 |
| | | let newTime = new Date().getFullYear() + "-" + lastPart |
| | | time = formatDateString(newTime) |
| | | } else if (lastPart.split("-").length === 3) { |
| | | // 年-月-日 |
| | | time = formatDateString(lastPart) |
| | | } |
| | | return time; |
| | | } |
| | | |
| | | function save(grabRequestList, packageName) { |
| | | let paltform = ''; |
| | | let uniqueNo = ''; |
| | | if ('com.ss.android.ugc.aweme'.equals(packageName)) { |
| | | // 抖音 --- dy-ningzhu97722 |
| | | paltform = '抖音' |
| | | uniqueNo = ecloud.getDeviceNo().substring(3) |
| | | } else if ('小红书'.equals(packageName)) { |
| | | // 小红书 ---- xhs-ningzhu97722 |
| | | paltform = '小红书' |
| | | uniqueNo = ecloud.getDeviceNo().substring(4) |
| | | } else if ('快手'.equals(packageName)) { |
| | | // 快手 ---- ks-ningzhu97722 |
| | | paltform = '快手' |
| | | uniqueNo = ecloud.getDeviceNo().substring(3) |
| | | } |
| | | for (let i = 0; i < grabRequestList.length; i++) { |
| | | let add = { |
| | | "tableNameEn": "grab_comment", |
| | | "columns": { |
| | | "task_id": ecloud.getTaskInfo().taskId, |
| | | "task_name": ecloud.getTaskInfo().taskName, |
| | | "device_no": ecloud.getDeviceNo(), |
| | | "nickname": grabRequestList[i].nickname, |
| | | "unique_no": uniqueNo, |
| | | "content": grabRequestList[i].comment, |
| | | "comment_time": grabRequestList[i].commentTime, |
| | | "platform": paltform, |
| | | "relation": grabRequestList[i].relation, |
| | | } |
| | | } |
| | | ecloud.dynamicAdd(add) |
| | | } |
| | | logd("getMessage 数据保存成功"); |
| | | } |
| | | |
| | | /** |
| | | * 记录埋点数据 |
| | | */ |
| | | function operaLog(num) { |
| | | let paltform = ''; |
| | | let operateType = ''; |
| | | let uniqueNo = ''; |
| | | if (num === 1) { |
| | | operateType = '应用启动' |
| | | } else if (num === 2) { |
| | | operateType = '点击消息' |
| | | } else if (num === 3) { |
| | | operateType = '点击互动消息' |
| | | } else if (num === 4) { |
| | | operateType = '脚本运行结束' |
| | | } |
| | | if ('com.ss.android.ugc.aweme'.equals(packageName)) { |
| | | // 斗音 |
| | | paltform = '抖音' |
| | | uniqueNo = ecloud.getDeviceNo().substring(3) |
| | | } else if ('小红书'.equals(packageName)) { |
| | | // 小红书 |
| | | paltform = '小红书' |
| | | uniqueNo = ecloud.getDeviceNo().substring(4) |
| | | } else if ('快手'.equals(packageName)) { |
| | | // 快手 |
| | | paltform = '快手' |
| | | uniqueNo = ecloud.getDeviceNo().substring(3) |
| | | } |
| | | let add = { |
| | | "tableNameEn": "trace", |
| | | "columns": { |
| | | "device_no": ecloud.getDeviceNo(), |
| | | "platform": paltform, |
| | | "unique_no": uniqueNo, |
| | | "post_name": '', |
| | | "nickname": '', |
| | | "keyword": '', |
| | | "operate_type": operateType, |
| | | "task_id": ecloud.getTaskInfo().taskId, |
| | | "task_name": ecloud.getTaskInfo().taskName, |
| | | } |
| | | } |
| | | ecloud.dynamicAdd(add) |
| | | logd("getMessage 数据保存成功"); |
| | | } |
| | | |
| | | /** |
| | | * 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(); |
| | | logd('弹窗已处理'); |
| | | } |
| | | } |
| | | sleep(3000); |
| | | } |
| | | }); |
| | | return true; |
| | | } |
| | | |
| | | // 获取当前日期 |
| | | function getCurrentDate() { |
| | | return new Date(); |
| | | } |
| | | |
| | | // 格式化日期为年-月-日 |
| | | function formatDate(date) { |
| | | const year = date.getFullYear(); |
| | | const month = String(date.getMonth() + 1).padStart(2, '0'); |
| | | const day = String(date.getDate()).padStart(2, '0'); |
| | | const format = 'yyyy-MM-dd' |
| | | return format |
| | | .replace('yyyy', year) |
| | | .replace('MM', month) |
| | | .replace('dd', day); |
| | | } |
| | | |
| | | // 格式化日期字符串的函数 |
| | | function formatDateString(dateString) { |
| | | // 使用正则表达式分割日期字符串 |
| | | const parts = dateString.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/); |
| | | |
| | | if (parts) { |
| | | // 提取年份、月份和日期 |
| | | const year = parts[1]; |
| | | const month = String(parseInt(parts[2], 10)).padStart(2, '0'); |
| | | const day = String(parseInt(parts[3], 10)).padStart(2, '0'); |
| | | |
| | | // 拼接成新的日期字符串 |
| | | return year + "-" + month + "-" + day; |
| | | } else { |
| | | // 如果日期字符串格式不正确,返回一个错误消息或默认值 |
| | | return 'Invalid date string format'; |
| | | } |
| | | } |
| | | |
| | | // 获取指定天数后的日期 |
| | | function getDateAfterDays(date, days) { |
| | | const newDate = new Date(date.getTime() + (days * 24 * 60 * 60 * 1000)); |
| | | return newDate; |
| | | } |
| | | |
| | | // 获取指定天数前的日期 |
| | | function getDateBeforeDays(date, days) { |
| | | return getDateAfterDays(date, -days); |
| | | } |
New file |
| | |
| | | //命中评论私信 |
| | | // 请勿让日志窗口遮挡屏幕 |
| | | |
| | | let packageName = 'com.ss.android.ugc.aweme'; |
| | | |
| | | var searchContent, messageWords, hitKeywords, everyNumber, total; //搜索词, 私信话术, 命中关键词, 单视频回复量, 总回复量 |
| | | |
| | | 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) { |
| | | messageWords = 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; |
| | | message(); //私信 |
| | | break; |
| | | } else { |
| | | loge('浏览失败'); |
| | | exit(); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } |
| | | } else { |
| | | loge('搜索失败'); |
| | | exit(); |
| | | } |
| | | |
| | | } else { |
| | | loge('输入失败'); |
| | | exit(); |
| | | } |
| | | } |
| | | } else { |
| | | loge('未找到搜索按钮'); |
| | | exit(); |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * description 私信评论用户 |
| | | * @param p {number} : 私信概率 |
| | | * @param everyNumber {number} : 单个视频回复数量 |
| | | * @param total {number} : 总回复数量 |
| | | */ |
| | | function message() { |
| | | let completedNumber = 0; //已私信总数 |
| | | var flag = false; |
| | | while (true) { |
| | | //寻找评论图标并点击 |
| | | toast('打开评论...'); |
| | | let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000); |
| | | 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); |
| | | var avatar = sub.previousSiblings()[0]; //头像节点 |
| | | hasKey = true; |
| | | toast('第' + (i + 1) + '条评论命中关键词,进行私信...'); |
| | | randomSleep(); |
| | | insertCommentsGot(comments, hitKeywords[n], t, ip); |
| | | if (avatar.click()) { |
| | | randomSleep(); |
| | | thread.execSync(function () { |
| | | send(); |
| | | num++; |
| | | completedNumber++; |
| | | }, 1000); |
| | | } |
| | | } |
| | | // }, 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 send() { |
| | | let result = false; |
| | | let follow = text("关注"); |
| | | let message_btn = text("私信").getOneNodeInfo(1000); |
| | | let title = text("账号已经注销").getOneNodeInfo(1000); |
| | | //判断是否关注用户 |
| | | let follow_btn = getNodeInfo(follow, 1000); |
| | | if (follow_btn[1]) { |
| | | follow_btn[1].click(); |
| | | logd('关注用户'); |
| | | sleep(4000); |
| | | //判断私密账户 |
| | | let private = textMatch(".*私密账号.*").getOneNodeInfo(1000); |
| | | let ok = text("知道了").getOneNodeInfo(1000); |
| | | if (private) { |
| | | ok.click(); |
| | | sleep(3000); |
| | | go_back(1); |
| | | } |
| | | } |
| | | //判断是否注销 |
| | | if (title) { |
| | | go_back(1); |
| | | result = false; |
| | | } else if (message_btn.click()) { |
| | | logd('进入私信'); |
| | | randomSleep(); |
| | | let input_selectors = clz("android.widget.EditText"); |
| | | let text = messageWords[random(0, messageWords.length - 1)]; |
| | | //寻找输入框 输入话术 |
| | | if (inputText(input_selectors, text)) { |
| | | sleep(4000); |
| | | let send_btn = desc("发送").getOneNodeInfo(1000); |
| | | if (send_btn.click()) { |
| | | randomSleep(); |
| | | logd("私信成功"); |
| | | go_back(2); |
| | | result = true; |
| | | } |
| | | } |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 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); |
| | | } |
New file |
| | |
| | | //命中评论回复 |
| | | // 请勿让日志窗口遮挡屏幕 |
| | | |
| | | let packageName = 'com.ss.android.ugc.aweme'; |
| | | |
| | | var searchContent, replyWords, hitKeywords, everyNumber, total; //搜索词, 回复话术, 命中关键词, 单视频回复量, 总回复量 |
| | | |
| | | 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); |
| | | 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()) { |
| | | 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); |
| | | } |