wechatWork

微信项目使用文档

项目启动说明

使用 node wechatWork/wechatMain.js <xx> 或者 npm run wechat 启动 使用前请确认已上传 任务文件

<xx> 为对应的机器序号

启动参数代码

const projectInd = Number(process.argv.slice(2)[0]) + indOffset
const indOffset = 120
const keepCookie = true
const packageName = 'com.tencent.mm'
const activityName = 'com.tencent.mm.ui.LauncherUI'
const robotName = `robot${projectInd}`
const projectName = `wechatWork`

启动参数说明

NameTypeexampleDescription
projectIndnumber0项目机器序号
indOffsetnumber120项目序号组(每20为一个项目)
keepCookiebooleantrue启动是否保留手机账号信息
packageNamestringcom.xxx.xxxapp包名
activityNamestringcom.xxx.xxx.MainActivityapp活动名
robotNamestringrobot0对应机器人名称
projectNamestringwechatWork项目名称

appium设置参数

const opts = {
    path: '/',
    port: 4723,
    capabilities: {
        "platformName": "Android",
        "appium:noReset": keepCookie,
        "appium:newCommandTimeout": "9999",
        "appium:automationName": "UiAutomator2",
        "appium:disableWindowAnimation": true,
        "appium:disableIdLocatorAutocompletion": true,
        "appium:limitXPathContextScope": false
    },
    logLevel: "error",
}

详见appium设置文档 https://appium.io/docs/en/latest/guides/caps/.

任务执行设置

const taskOpt = {
    bucket: 'bucket-task', //amz bucket名称
    totalRetry: 86400,  //获取新任务的尝试次数
    taskRetry: 86400,   //等待任务开始的尝试次数
    totalRetryGap: 10,  //单位秒,支持小数
    taskRetryGap: 10,  //单位秒,支持小数
}

任务类型介绍

const myCapacity = async (act, type, data) => {
    let result = ''
    switch (type) {
        case 'searchVideo':
            result = await searchVideo(act, data); //在app内搜索某个视频
            break;
        case 'searchUser':
            result = await searchUser(act, data); //在app内搜索某个用户
            break;
        case 'releaseVideo':
            result = await releaseVideo(act, data); //发布视频
            break;
        case 'replyMessage':
            result = await replyMessage(act, data); //处理消息私信
            break;
        case 'groupChat':
            result = await groupChat(act, data); //群聊功能
            break;
        case 'clearCache':
            result = await clearCache(act); //清理app缓存
            break;
        case 'clearDailyFollow':
            result = await clearDailyFollow(projectName); //重置每日关注计数
            break;

        default:
            break;
    }
    return result
}

读取任务文件中todoListtype分别使用各个功能

任务文件示例

  1. missionStart 参数为false时,代码会循环等待直到其更新为true
  2. name 参数为json文件名,同时可在 bucket-task 上查看

name参数说明

NameexampleDescription
robot120robot120项目机器序号
worklist01first,second,***识别文件名并决定优先读取顺序
douyindouyin,wechat,xiaohongshu项目名称
  1. todoList 参数为任务列表,代码会依次识别数组内的type执行对应的功能
{
  "missionStart": true, // 任务开始的标志
    "name": "robot120--worklist01--douyin", // 任务的名称
    "todoList": [
        {
            "type": "searchVideo",// 任务类型搜索视频
            "data": {
                "location": [
                    "幻兽帕鲁",
                    "幻兽帕鲁",
                    "幻兽帕鲁",
                    "palworld",
                    "帕鲁世界",
                    "帕鲁服务器",
                    "幻兽帕鲁服务器",
                    "幻兽帕鲁攻略",
                    "幻兽帕鲁修改器"
                ], //随机一个搜索关键字
                "addLikes": true,//是否点赞
                "comment": "", //评论内容
                "review": null, //恢复任务标识
                "access": { //遍历评论区
                    "userList": [], //查重数组
                    "follow": false, //是否关注
                    "limit": 100, //限制访问人数
                    "chat": false //是否发送ai私信
                }
            }
        },
        {
            "type": "searchUser",// 任务类型搜索用户
            "data": {
                "userName": "嘟嘟助手团_97965599632", //用户名称或id
                "follow": false //进入主页是否关注
            }
        },
        {
            "type": "replyMessage",// 任务类型处理消息
            "data": [
                {
                    "type": "notice" //查看系统消息
                },
                {
                    "type": "reply" //回复私信
                },
                {
                    "type": "search", //搜索用户并发送消息
                    "userName": "Starnes",
                    "text": "测试自动化2"
                }
            ]
        },
        {
            "type": "releaseVideo", // 任务类型
            "data": {
                "url": "https://video-bucket.s3.cn-northwest-1.amazonaws.com.cn/pal-promo.mp4", // 视频的URL地址
                "title": "帕帕云,一键部署服务器轻松玩转幻兽帕鲁。", // 视频的标题
                "tags": [
                    "#幻兽帕鲁",
                    "#palworld",
                    "#帕鲁服务器",
                    "#steam游戏",
                    "#游戏鉴赏家"
                ], // 视频的标签数组
                "location": "", // 视频的地理位置信息
                "permission": "公开 · 所有人可见", // 视频的权限设置
                "activity": "", // 视频的参与活动内容
                "link": "" // 视频的公众号连接
            }
        }
    ]
}

代码运行说明

1. checkFile 检查项目所需文件是否存在,如果不存在则创建文件,并初始化数据结构。

await checkFile(projectName);

Source : douyinWork/douyinMain.js,line 407

2. robotApi 查询robot信息。

let robotStat = await robotApi.getInfo();

Source : douyinWork/douyinMain.js,line 409

3. 项目代码卡死重启功能,通过重新创建client实例实现,如有报错则检查adb连接

for (let running = 0; running < 5; running++) {
    try{
        //...
    }
    catch{
            for (let i = 0; i < 99999; i++) {
                let checkAdb = await cmd.runSync(`adb devices`);
                let adbData = checkAdb.data.replace("devices", "")
                if (adbData.includes("device")) {
                    console.log(adbData);
                    break
                }
                else {
                    if (i % 2 === 0) { console.log('adb 断开了', i, adbData); }
                }
                await sleep(2);
            }
    }
}

Source : douyinWork/douyinMain.js,line 469

4. 创建wdioclient 实例,并创建act类方便使用appium代码。

const client = await wdio.remote(opts);
const act = new MyAction(client);

Source : douyinWork/douyinMain.js,line 424

5. 检测app的状态判断是否拉起app。

            let start = await client.queryAppState(packageName)
            if (start === 1) {
                console.log('启动app');
                await client.startActivity(packageName, activityName);
            }
            else if (start === 3 || start === 2) {
                console.log('后台拉出app');
                await client.activateApp(packageName);
            }
            else if (start === 4) {
                if (robotStat.step < 4) {
                    await client.terminateApp(packageName);
                    await new Promise(resolve => setTimeout(resolve, 2000));
                    console.log('重新打开app');
                    await client.startActivity(packageName, activityName);
                }
                else { console.log('app已启动保持状态'); }
            }

Source : douyinWork/douyinMain.js,line 425

6. 调用 main appium脚本主程序。

let runningRes = await main(robotStat, act);
const main = async (robotStat, act, restart) => {
    //....
}

Source : douyinWork/douyinMain.js,line 240

7. main: 获取手机号信息。

        let phonelist = await phoneListApi.getInfo();
        if (!phonelist[projectInd]) return `get phonelist Fail`
        else console.log('手机号信息', phonelist[projectInd]);

8. main: 启动appium打开app

        let startC = await startChecking(act, restart);
        if (startC === 'error') return `startChecking Error ==>> ${startC}`

9. main: 注册/登录

根据需求登录或注册账号,检测到登录完成进入主页时会返回true,否则返回false并停止main运行。

 if (robotStat.step === 1) {
    //...
    let update = await robotApi.updateInfo(robotStat);
    if (!update) return `signUp Update Fail`
 }

9. main: 读取任务文件执行功能

获取任务文件,读取任务文件内容并调用myCapacity执行对应功能。

    let task = await getLists(queue);
    let todoList = await getTodoList(task);
    log.notice(`开始执行任务列表, ${i} ==> ${task}`)
    let fullComplete = true //任务无错检测
    for (let n = 0; n < todoList.length; n++) {
        let res = await myCapacity(act, todoList[n].type, todoList[n].data);
        if (res.main !== 'over') {
            fullComplete = false
            errorTimes++
        }
        else {
            errorTimes = 0
        }
        await updateTask(task, res, todoList[n].type);
        log.notice(`任务执行完毕 ==> ${todoList[n].type}`);
    }
    log.notice(`任务列表执行完毕, ${i} ==> ${task}`);
    if (fullComplete) {
        log.notice(`所有任务都完成了`);
        await updateTask(task, null, null, true);
    }

9. main: 任务完成后续处理

防崩溃检测,检测休息弹窗等功能。

    await act.waitForElement(['text', '下线提醒'], 3000);
    log.warning('被踢下线了');
    await act.clickElement(['text', '忽略提醒'], 3000);
    log.warning('出现休息弹窗');
    let start = await act.client.queryAppState(packageName)
    if (start !== 4 || errorTimes > 2) {
        log.warning(`~~程序崩溃,重启app, ${errorTimes}`);
        await act.client.startActivity(packageName, activityName);
        await startChecking(act, restart);
        n--
    }