panchengyong
10 days ago b2d3f7caf927e5b83ec52efb74f1f818dbb15236
commit | author | age
b2d3f7 1 /**
P 2  * description 命中评论私信
3  * 请勿让日志窗口遮挡屏幕
4  * @type {string}
5  */
bc5e1e 6 let packageName = 'com.ss.android.ugc.aweme';
X 7
8 var searchContent, messageWords, hitKeywords, everyNumber, total; //搜索词, 私信话术, 命中关键词, 单视频回复量, 总回复量
9
10 getECloudData(); //获取任务数据
11
12
13 /**
14  * description 获取云控参数
15  * @return {boolean} : 返回是否成功
16  */
17 function getECloudData() {
18     let result = false;
19     let hasData = true, value;
20     let data = new Array();
21     let group = [{
22         "groupName" : "短视频代运营搜索词",
23         "dataName" : "斗因-视频搜索词"
24     },{
25         "groupName" : "短视频代运营话术",
26         "dataName" : "斗因-私信话术"
27     },{
28         "groupName" : "短视频代运营命中关键词",
29         "dataName" : "斗因-评论命中关键词"
30     },{
31         "groupName" : "短视频代运营执行数量",
32         "dataName" : "斗因-评论执行数量"
33     }];
34     //通过数据组名或数据名称取得数据
35     for (let i = 0; i < group.length; i++) {
36         data = ecloud.getData(group[i]);
37         if (data[0]) {
38             if (i == 0) {
39                 searchContent = value = data[0].content.split("|");
40             } else if (i == 1) {
41                 messageWords = value = data[0].content.split("\n");
42             } else if (i == 2) {
43                 hitKeywords = value = data[0].content.split("|");
44             } else if (i == 3)  {
45                 let array = value = data[0].content.split("|");
46                 everyNumber = array[0];
47                 total = array[1];
48             }
49             if (!value || value.length == 0) {
50                 hasData = false;
51                 loge('未设置' + group[i].dataName);
52                 break;
53             }
54         } else {
55             hasData = false;
56             loge('未获取' + group[i].dataName);
57             break;
58         }
59     }
60     if (hasData) {
61         logi('已获取任务数据,开始执行...');
62         randomSleep();
63         result = true;
64         launch(packageName, 6000, 3); //打开抖音
65     }
66     return result;
67 }
68
69
70 /**
71  * description 通过包名启动应用
72  * @param packageName {string} : 应用包名
73  * @param delay {number} : 启动后等待时长(毫秒)
74  * @param startNum {number} : 重试次数
75  * @return {boolean} : 返回是否成功
76  */
77 function launch(packageName, delay, startNum) {
78     let result = false;
79     //判断应用的包名是否存在
80     if (utils.isAppExist(packageName)) {
81         //判断应用是否在前台
82         if (getRunningPkg() == null) {
83             loge('请开启辅助功能权限');
84         } else if (getRunningPkg() === packageName) {
85             logi('应用已经在前台');
86             result = true;
87             search(); //搜索视频
88         } else {
89             logi('启动应用...');
90             let alert_selectors = text("允许");
91             let num = 0;
92             //判断应用是否启动成功
93             while (num < startNum) {
94                 if (getRunningPkg() === packageName) {
95                     insertTrace('', '', '', "应用启动");
96                     logi('启动成功');
97                     result = true;
98                     search(); //搜索视频
99                     break;
100                 } else if (has(alert_selectors)) {
101                     //初次打开应用 可能会弹出是否允许打开的弹窗
102                     let node = alert_selectors.getOneNodeInfo(3000);
103                     if (node) {
104                         node.click();
105                     }
106                 } else {
107                     utils.openApp(packageName);
108                     sleep(delay);
109                     num++;
110                 }
111             }
112         }
113         alert(); //应用启动后处理弹窗
114     } else {
115         toast('应用未安装');
116     }
117     return result;
118 }
119
120
121 /**
122  * description 根据关键词搜索视频
123  * @return {boolean} : 返回是否成功
124  */
125 function search() {
126     //定位到首页
127     execSync(function () {
128         isHome();
129     }, 1000);
130     let result = false;
131     //寻找搜索按钮并点击
132     logi('开始搜索...');
133     let search = descMatch(".*搜索.*").getOneNodeInfo(5000);
134     if (search) {
135         if (search.click()) {
136             randomSleep();
137             //寻找输入框 输入搜索词
138             logi('输入搜索内容...');
139             let input_selectors = clz("android.widget.EditText").getOneNodeInfo(5000);;
140             let keyword = searchContent[random(0, searchContent.length - 1)];
141             if (input_selectors) {
142                 if (input_selectors.inputText(keyword)) {
143                     randomSleep();
144                     //点击搜索
145                     if (search.click()) {
146                         insertTrace('', '', keyword, "搜索");
147                         randomSleep();
148                         logi('搜索完成');
149                         //进入视频页
150                         let tab_node = clz("android.widget.Button").getNodeInfo(5000);
151                         if (tab_node) {
152                             for (let i = 0; i < tab_node.length; i++) {
153                                 if (tab_node[i].text === "视频") {
154                                     if (tab_node[i].click()) {
155                                         randomSleep();
156                                         //浏览视频
157                                         let video_node = depth(20).getOneNodeInfo(5000); //根据深度匹配
158                                         logi('浏览视频...');
159                                         if (video_node) {
160                                             if (video_node.click()) {
161                                                 randomSleep();
162                                                 let nameSelectors = id("com.ss.android.ugc.aweme:id/title").getOneNodeInfo(2000);
163                                                 let postSelectors = id("com.ss.android.ugc.aweme:id/desc").getOneNodeInfo(2000);
164                                                 insertTrace(postSelectors.text, nameSelectors.text, '', "搜索");
165                                                 result = true;
166                                                 message(); //私信
167                                                 break;
168                                             } else {
169                                                 loge('浏览失败');
170                                                 exit();
171                                             }
172                                         }
173                                     }
174                                 }
175                             }
176                         }
177                     } else {
178                         loge('搜索失败');
179                         exit();
180                     }
181
182                 } else {
183                     loge('输入失败');
184                     exit();
185                 }
186             }
187         } else {
188             loge('未找到搜索按钮');
189             exit();
190         }
191     }
192     return result;
193 }
194
195
196 /**
197  * description 私信评论用户
198  * @param p {number} : 私信概率
199  * @param everyNumber {number} : 单个视频回复数量
200  * @param total {number} : 总回复数量
201  */
202 function message() {
203     let completedNumber = 0; //已私信总数
204     var flag = false;
205     while (true) {
206         //寻找评论图标并点击
207         toast('打开评论...');
208         let comment_icon = descMatch(".*评论.*").getOneNodeInfo(5000);
209         if (comment_icon) {
210             if (comment_icon.click()) {
211                 var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
212                 if (result) {
213                     randomSleep();
214                     toast('放大评论区');
215                     let btn = desc("放大评论区").visible(true).getOneNodeInfo(3000);
216                     if (btn) {
217                         if (btn.click()) {
218                             flag = true;
219                             randomSleep();
220                             var result = id("com.ss.android.ugc.aweme:id/content").getNodeInfo(2000);
221                             let num = 0 //回复数量
222                             while (flag) {
223                                 for (var i = 0; i < result.length; i++) {
224                                     var hasKey = false;
225                                     if (num < everyNumber) {
226                                         toast('浏览第' + (i + 1) + '条评论...');
227                                         var comments = result[i].text; //评论内容
228                                         for (var n = 0; n < hitKeywords.length; n++) {
229                                             // execSync(function () {
230                                             if (comments.includes(hitKeywords[n])) {
231                                                 var sub = result[i].nextSiblings()[0]; //评论节点
232                                                 var t = sub.child(0);
233                                                 var ip = sub.child(1);
234                                                 var avatar = sub.previousSiblings()[0]; //头像节点
235                                                 hasKey = true;
236                                                 toast('第' + (i + 1) + '条评论命中关键词,进行私信...');
237                                                 randomSleep();
238                                                 insertCommentsGot(comments, hitKeywords[n], t, ip);
239                                                 if (avatar.click()) {
240                                                     randomSleep();
241                                                     thread.execSync(function () {
242                                                         send();
243                                                         num++;
244                                                         completedNumber++;
245                                                     }, 1000);
246                                                 }
247                                             }
248                                             // }, 1000);
249                                         }
250                                         if (i == result.length - 1 && !hasKey) {
251                                             num++;
252                                             completedNumber++;
253                                             toast('当前视频未找到命中评论');
254                                             randomSleep();
255                                         }
256                                     } else if (Number(completedNumber) === Number(total)) {
257                                         toast("任务完成");
258                                         shell.stopApp(packageName); //关闭抖音
259                                         home();
260                                         exit()
261
262                                     } else {
263                                         let btn = desc("缩小评论区").visible(true).getOneNodeInfo(3000);
264                                         if (btn.click()) {
265                                             randomSleep();
266                                         }
267                                         flag = false;
268                                         go_back(1);
269                                         toast('当前视频私信完成,下一个视频...');
270                                         randomSleep();
271                                         swiper(); //下一个视频
272                                         break
273                                         break;
274                                     }
275                                 }
276                             }
277
278                         }
279                     }
280                 } else {
281                     toast('未找到评论');
282                     randomSleep();
283                     go_back(2);
284                     swiper(); //下一个视频
285                     // break;
286                 }
287             }
288         }
289     }
290 }
291
292
293 /**
294  * description 发私信消息
295  * @return {boolean} : 返回是否成功
296  */
297 function send() {
298     let result = false;
299     let follow = text("关注");
300     let message_btn = text("私信").getOneNodeInfo(1000);
301     let title = text("账号已经注销").getOneNodeInfo(1000);
302     //判断是否关注用户
303     let follow_btn = getNodeInfo(follow, 1000);
304     if (follow_btn[1]) {
305         follow_btn[1].click();
306         logd('关注用户');
307         sleep(4000);
308         //判断私密账户
309         let private = textMatch(".*私密账号.*").getOneNodeInfo(1000);
310         let ok = text("知道了").getOneNodeInfo(1000);
311         if (private) {
312             ok.click();
313             sleep(3000);
314             go_back(1);
315         }
316     }
317     //判断是否注销
318     if (title) {
319         go_back(1);
320         result = false;
321     } else if (message_btn.click()) {
322         logd('进入私信');
323         randomSleep();
324         let input_selectors = clz("android.widget.EditText");
325         let text = messageWords[random(0, messageWords.length - 1)];
326         //寻找输入框 输入话术
327         if (inputText(input_selectors, text)) {
328             sleep(4000);
329             let send_btn = desc("发送").getOneNodeInfo(1000);
330             if (send_btn.click()) {
331                 randomSleep();
332                 logd("私信成功");
333                 go_back(2);
334                 result = true;
335             }
336         }
337     }
338     return result;
339 }
340
341
342 /**
343  * description 异步执行线程 处理弹窗
344  * @return {boolean} : 返回是否成功
345  */
346 function alert() {
347     thread.execAsync(function () {
348         logd('启动线程,查找弹窗');
349         let btnText = new Array(
350             "下次再说",
351             "以后再说",
352             "关闭",
353             "允许",
354             "暂不",
355             "暂时不要",
356             "我知道了",
357             "知道了",
358             "取消",
359         );
360         while (true) {
361             for (let i = 0; i < btnText.length; i++) {
362                 logd('检查弹窗...');
363                 let node = text(btnText[i]).getOneNodeInfo(1000);
364                 if (node) {
365                     node.click();
366                     toast('弹窗已处理');
367                 }
368             }
369             sleep(4000);
370         }
371     });
372     return true;
373 }
374
375
376 /**
377  * description 定位到首页
378  * @return {boolean} : 返回是否成功
379  */
380 function isHome() {
381     let result = false;
382     while (true) {
383         var home_selectors = text("首页").getOneNodeInfo(3000); //首页按钮
384         var message_selectors = text("消息").getOneNodeInfo(3000); //消息按钮
385         //判断是否在首页
386         if (home_selectors && message_selectors) {
387             var follow_selectors = text("关注"); //关注按钮
388             var recommend_selectors = text("推荐"); //推荐按钮
389             if (has(follow_selectors) && has(recommend_selectors)) {
390                 toast('已定位首页');
391                 randomSleep();
392                 result = true;
393                 break;
394             } else {
395                 home_selectors.click();
396                 sleep(3000);
397             }
398         } else {
399             toast('返回首页...');
400             //返回上一页
401             go_back(1);
402         }
403     }
404     return result;
405 }
406
407
408 /**
409  * description 自定义返回函数
410  * @param page {number} : 返回页数
411  */
412 function go_back(page) {
413     let count = 0;
414     while (count < page) {
415         back();
416         count++;
417         randomSleep();
418     }
419 }
420
421
422 /**
423  * description 随机暂停时间
424  */
425 function randomSleep() {
426     let min = Math.ceil(3);
427     let max = Math.floor(6);
428     let time = (Math.floor(Math.random() * (max - min + 1)) + min) * 1000;
429     sleep(time);
430 }
431
432
433 /**
434  * description 插入埋点
435  * @param unique_id {string} : 用户唯一编号
436  * @param post_name {string} : 作品名称
437  * @param nickname {string} : 用户昵称
438  * @param keyword {string} : 搜索关键词
439  * @param operate_type {string} : 操作类型
440  */
441 function insertTrace(post_name, nickname,keyword, operate_type) {
442     let time = getDate();
443     var deviceNo = ecloud.getDeviceNo(); //设备编号
444     var unique_id = deviceNo.slice(3);
445     let add = {
446         "tableNameEn": "trace",
447         "columns": {
448             "device_no" : deviceNo, //设备编号
449             "operate_time" : time, //操作时间
450             "platform" : "抖音", //所属平台
451             "unique_no" : unique_id, //用户唯一编号
452             "post_name" : post_name, //作品名称
453             "nickname" : nickname, //用户昵称
454             "keyword" : keyword, //搜索关键词
455             "operate_type" : operate_type, //操作类型
456             "task_id": ecloud.getTaskInfo().taskId,
457             "task_name": ecloud.getTaskInfo().taskName
458         }
459     }
460     ecloud.dynamicAdd(add);
461 }
462
463 /**
464  * description 插入命中作品评论
465  * @param content {string} : 线索
466  * @param got_word {string} : 命中词
467  * @param comment_datetime {string} : 评论时间
468  * @param province {string} : 省
469  */
470 function insertCommentsGot(content, got_word, comment_datetime,province) {
471     let time = getDate();
472     let add = {
473         "tableNameEn": "dy_comments_got",
474         "columns": {
475             "task_id" : '', //任务id
476             "task_name" : '', //任务名
477             "title" : "", //视频标题
478             "dy_nickname" : '', //抖音昵称
479             "content" : content, //线索
480             "tel" : '',//手机号
481             "got_word" : got_word ,//命中词
482             "comment_datetime" : comment_datetime, //评论时间
483             "grab_datetime" : time, //挖掘时间
484             "province" : province, //省
485             "task_id": ecloud.getTaskInfo().taskId,
486             "task_name": ecloud.getTaskInfo().taskName
487         }
488     }
489     ecloud.dynamicAdd(add);
490 }
491
492
493 /**
494  * description 获取当前时间
495  * @return {string} : 返回时间
496  */
497 function getDate() {
498     let date = new Date();
499     let sign2 = ":";
500     let year = date.getFullYear() // 年
501     let month = date.getMonth() + 1; // 月
502     let day = date.getDate(); // 日
503     let hour = date.getHours(); // 时
504     let minutes = date.getMinutes(); // 分
505     let seconds = date.getSeconds() //秒
506     let weekArr = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天'];
507     let week = weekArr[date.getDay()];
508     // 给一位数的数据前面加 “0”
509     if (month >= 1 && month <= 9) {
510         month = "0" + month;
511     }
512     if (day >= 0 && day <= 9) {
513         day = "0" + day;
514     }
515     if (hour >= 0 && hour <= 9) {
516         hour = "0" + hour;
517     }
518     if (minutes >= 0 && minutes <= 9) {
519         minutes = "0" + minutes;
520     }
521     if (seconds >= 0 && seconds <= 9) {
522         seconds = "0" + seconds;
523     }
524     return year + "-" + month + "-" + day + " " + hour + sign2 + minutes + sign2 + seconds;
525 }
526
527
528 /**
529  * description 滑动视频
530  * @return {boolean} : 返回是否成功
531  */
532 function swiper(){
533     let result = false;
534     //设定坐标 适配全分辨率
535     let x = device.getScreenWidth() * 7 / 10;
536     let y = device.getScreenHeight() * 8 / 10;
537     let x1 = device.getScreenWidth() * 7 / 10;
538     let y1 = device.getScreenHeight() * 1.5 / 10
539
540     if (rnd_Swipe(x,y,x1,y1,100,200,200)) {
541         sleep(3000);
542         logd("滑动完成");
543         result = true;
544     }
545     return result;
546 }
547
548
549 /**
550  * description 仿真随机带曲线滑动
551  */
552 function rnd_Swipe(qx, qy, zx, zy,time, times,timess) {
553     //qx, qy, zx, zy, time 代表起点x,起点y,终点x,终点y,times,timess =随机时间(times,timess)
554     let time1,xxy,point,dx0,dx1,dx2,dx3,xxyy
555     time1=random(times,timess)
556
557     xxy = [];
558     point = [];
559     dx0 = {
560         "x": qx,
561         "y": qy
562     }
563
564     dx1 = {
565         "x": random(qx - 100, qx + 100),
566         "y": random(qy , qy + 50)
567     }
568     dx2 = {
569         "x": random(zx - 100, zx + 100),
570         "y": random(zy , zy + 50),
571     }
572     dx3 = {
573         "x": zx,
574         "y": zy
575     }
576     for (let i = 0; i < 4; i++) {
577         eval("point.push(dx" + i + ")");
578     }
579     for (let i = 0; i < 1; i += 0.08) {
580         xxyy = [parseInt(bezier_curves(point, i).x), parseInt(bezier_curves(point, i).y)]
581         xxy.push(xxyy);
582     }
583     gesture(xxy,time, time1);
584
585     return true;
586 }
587
588
589 /**
590  * description 贝赛尔曲线
591  */
592 function bezier_curves(cp, t) {
593     let cx,bx,ax,cy,by,ay,tSquared,tCubed,result
594     cx = 3.0 * (cp[1].x - cp[0].x);
595     bx = 3.0 * (cp[2].x - cp[1].x) - cx;
596     ax = cp[3].x - cp[0].x - cx - bx;
597     cy = 3.0 * (cp[1].y - cp[0].y);
598     by = 3.0 * (cp[2].y - cp[1].y) - cy;
599     ay = cp[3].y - cp[0].y - cy - by;
600
601     tSquared = t * t;
602     tCubed = tSquared * t;
603     result = {
604         "x": 0,
605         "y": 0
606     }
607     result.x = (ax * tCubed) + (bx * tSquared) + (cx * t) + cp[0].x;
608     result.y = (ay * tCubed) + (by * tSquared) + (cy * t) + cp[0].y;
609     return result;
610 }
611
612
613 /**
614  * description 手势
615  */
616 function gesture(swipeList,time,time1) {
617     let touch1 ,touch2,x,i
618     touch1 = [{"action": 0, "x": swipeList[0][0], "y": swipeList[0][1], "pointer": 1, "delay": time}]
619
620     for (i in swipeList) {
621         ++i;
622         if (i===swipeList.length-2) {break;}
623         touch1.push({"action": 1, "x": swipeList[i][0], "y": swipeList[i][1], "pointer": 1, "delay": time});
624     }
625     touch1.push({"action": 2, "x": swipeList[swipeList.length-1][0], "y": swipeList[swipeList.length-1][1], "pointer": 1, "delay": time})
626
627     x = multiTouch(touch1, null, null, time1);
628     logd('仿真滑动:'+x);
629     sleep(3000);
630 }