美文网首页aardio
webview2抖音视频自动发布

webview2抖音视频自动发布

作者: LCSan | 来源:发表于2023-07-20 21:51 被阅读0次

    aardio的webview2同步方式,通过js,cdp协同完成。几个重要点记录一下:
    1、webview中异步、同步方法不能混用,同步会阻塞消息队列。这里要用cpd是同步方法,因此全部舍弃异步方法;
    2、文件上传,用DOM.setFileInputFiles方法,不用模拟文件弹框,直接设置文件即可上传;
    3、抖音的视频标题框是封装控件,必须模拟点击获取焦点。这里用Input发送键盘、鼠标、指令方式,模拟鼠键操作;
    4、cdp默认是css选择器,通过Runtime.evaluate以xpath方式执行js获取nodeId,再执行其他cdp命令传参。

    //自动化
    import win.ui;
    /*DSG{{*/
    var winform = win.form(text="抖音自动发布";right=759;bottom=469;bgcolor=16777215;border="thin")
    winform.add()
    /*}}*/
    
    import web.view;
    import web.json;
    import console;
    
    function enableEdit(wb){
        // 获取编辑框坐标
        var rect = wb.eval(`JSON.stringify(document.querySelector("div#root div.editor-kit-root-container > div > div").getBoundingClientRect())`);
        rect = web.json.parse(rect);
        // 鼠标左键点击,[x,y]坐标
        wb.cdp("Input.dispatchMouseEvent",{type="mousePressed";x=rect["x"]+10;y=rect["y"]+10;button="left"})    
    }
    
    
    // 输入文本
    function addSendMsg(wb,msg){
        // CDP:模拟输入文本
        wb.cdp("Input.insertText",{text=msg})
    }
    
    // 添加抖音用户
    function addSendUser(wb,userId){
        if(string.startWith(userId,'@')){
            userId = string.right(userId,-2)
        }
        addSendMsg(wb, "@" ++ userId)
        // 等待选人
        wb.waitEle(`div.editor-kit-root-container div.mention-suggest-mount-dom img`);
        // 选人
        wb.eval(`document.evaluate('.//span[contains(string(),"抖音号 ` + userId + `")]',document).iterateNext().click()`)
    }
    
    // 获取输入总长度
    function getMsgLength(wb){
        var data = wb.eval(`document.querySelector("div.toolbar > div:nth-child(2)").innerText.match(/\d+/ig)`); 
        if(tonumber(data[1]) > tonumber(data[2])){
            // 必须要点一下编辑框才能撤销
            enableEdit(wb)
            // CDP:模拟命令,撤销命令
            wb.cdp("Input.dispatchKeyEvent",{
                type="rawKeyDown";
                commands={"undo","undo"}
            })
    
            return false; 
        }
        return true; 
    }
    
    
    function uploadVideo(wb,mp4,msgs){
        
        //console.log("2222");
        // 等待上传框
        wb.waitEle(`input[type="file"]`);
        sleep(1000)
        // 获取控件
        var file = wb.cdpQuery(`input[type="file"]`);
        // 设置文件路径,上传
        wb.cdp("DOM.setFileInputFiles",{
            files = { mp4 };
            nodeId = file.nodeId;
        })
        
        // 等待编辑框
        wb.waitEle("div#root div.editor-kit-root-container");
        
        
        // 等待3秒
        sleep(1000)
        enableEdit(wb)
        var flag;   
        // 发消息
        for(k,v in msgs){
            if(string.startWith(v,'@')){
                addSendUser(wb,v)
            }else {
                addSendMsg(wb,v)
            }
            flag = getMsgLength(wb);
            //console.log(flag);
            if(!flag){
                break
            }
        }
        sleep(1000)
        // 勾选不允许下载
        wb.eval(`document.querySelector('div[class^="download-content"] input[type="checkbox"][value="0"]').click()`);
        
        // 等待重新上传框子,说明传完
        wb.waitEle(`#root > div > div > div[class^="content-body-"] > div[class^="preview-"] > div > div > div > div[class^="long-card-"]`);
        
        
        // 发布按钮,滚动到可视区域 
        var dd = wb.cdp("Runtime.evaluate",{
            expression = `document.evaluate(".//button[text()='发布']",document).iterateNext()`;
        });
        
        wb.cdp("DOM.scrollIntoViewIfNeeded",{
            objectId = dd.result.objectId;
        });
    
    
        // 发布视频
        wb.eval(`document.evaluate("//button[text()='发布']",document).iterateNext().click()`);
    }
    
    // 要发布的视频地址
    var mp4 = "mp4路径";
    // 视频title。文字,@抖音号。抖音号自动转成@人
    var msgs = {`测试一段文字,测试@人:`,"@77440681","@77440682","@77440683","@77440684"}; 
    
    // 初始化浏览器
    var wb = web.view(winform,`\userdata`); 
    winform.show();
    // 设置禁用选项,关闭右键,开发工具,状态栏
    wb.enableDefaultContextMenus(false);
    wb.enableDevTools(false);
    wb.enableStatusBar(false);
    
    //添加网页默认加载脚本,禁止弹出新窗口
    wb.preloadScript("window.open =  function(url){ window.location.href = url; } ")
    
    // 打开上传页面
    wb.go("https://creator.douyin.com/creator-micro/content/upload");
    wb.wait("");
    
    var flag = true;
    while(flag){
        select(wb.location) {
            case "https://creator.douyin.com/creator-micro/content/upload" {
                uploadVideo(wb,mp4,msgs)
                flag = false;
            }
            case "https://creator.douyin.com/creator-micro/home" {
                            // 登录成功,跳转到上传页面
                wb.go("https://creator.douyin.com/creator-micro/content/upload");
                wb.wait("creator-micro/content/upload");
                //console.log("222")
            }
            case "https://creator.douyin.com/" {
                            // 没有登录情况下,人工登录
                wb.waitEle("span.login")
                wb.eval(`document.querySelector("span.login").click()`)              
                wb.wait("creator-micro/home");
                //console.log("3333")
            }
        }
    }
    
    win.loopMessage();
    

    另外异步方式的实现,不稳定,记录一下。

    //waitEle 用法演示
    import win.ui;
    /*DSG{{*/
    var winform = win.form(text="抖音自动发帖";right=1097;bottom=759)
    winform.add(
    btn_video={cls="plus";text="视频目录";left=784;top=688;right=880;bottom=720;align="left";color=3947580;disabled=1;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF07C';notify=1;textPadding={left=25};z=6};
    btn_xls={cls="plus";text="Excel文件";left=784;top=656;right=880;bottom=688;align="left";color=3947580;disabled=1;dr=1;dt=1;font=LOGFONT(h=-13);iconStyle={align="left";font=LOGFONT(h=-13;name='FontAwesome');padding={left=8}};iconText='\uF07C';notify=1;textPadding={left=25};z=8};
    button_clean={cls="button";text="清空";left=1000;top=656;right=1096;bottom=680;disabled=1;z=4};
    button_start={cls="button";text="开始";left=888;top=656;right=984;bottom=680;disabled=1;z=3};
    edit_log={cls="edit";left=890;top=2;right=1096;bottom=648;color=128;disabled=1;edge=1;multiline=1;readonly=1;z=2};
    edit_sleep={cls="edit";text="2000";left=336;top=680;right=448;bottom=720;disabled=1;edge=1;num=1;z=12};
    edit_sn={cls="edit";left=72;top=728;right=328;bottom=752;edge=1;readonly=1;z=14};
    edit_tips={cls="edit";left=16;top=680;right=328;bottom=720;disabled=1;edge=1;multiline=1;z=9};
    edit_video={cls="plus";left=456;top=688;right=784;bottom=714;align="left";border={bottom=1;color=-6908266};disabled=1;dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-13);textPadding={top=6;bottom=2};z=5};
    edit_vip={cls="edit";left=392;top=728;right=872;bottom=752;edge=1;z=16};
    edit_xls={cls="plus";left=456;top=656;right=784;bottom=682;align="left";border={bottom=1;color=-6908266};disabled=1;dl=1;dr=1;dt=1;editable=1;font=LOGFONT(h=-13);textPadding={top=6;bottom=2};z=7};
    static={cls="static";left=0;top=0;right=889;bottom=651;transparent=1;z=1};
    static2={cls="static";text="话术";left=16;top=656;right=80;bottom=672;color=3947580;font=LOGFONT(h=-14);group=1;transparent=1;z=10};
    static3={cls="static";text="机器码:";left=16;top=736;right=72;bottom=760;transparent=1;z=13};
    static4={cls="static";text="搜索间隔(毫秒)";left=336;top=656;right=432;bottom=672;color=3947580;font=LOGFONT(h=-14);group=1;transparent=1;z=11};
    static6={cls="static";text="激活码:";left=336;top=736;right=392;bottom=760;transparent=1;z=15};
    static7={cls="static";text="有效期至:";left=880;top=736;right=952;bottom=760;transparent=1;z=17};
    static_tm={cls="static";text="-";left=944;top=736;right=1072;bottom=760;transparent=1;z=18}
    )
    /*}}*/
    
    import winex;
    import key;
    import config;
    import fsys;
    import mouse;
    import winex.mouse;
    import winex.key;
    import com.excel; 
    import web.view;
    import win.timer;
    import myplu.vip;
    
    // 自动保存配置文件
    winform.bindConfig( config.winform,{
        edit = "text";
        radiobutton = "checked";
        checkbox = "checked";
        combobox = "selIndex";
        plus ={
            ["^chk"] = "checked";
            ["^edit"] = "text";
        };
    } );
    
    // 定时器
    var timer = win.timer(winform); 
    // 间隔1秒
    timer.setInterval(1000);
    // 更新计时
    timer.onTimer = function(hwnd,msg,id,tick){
        winform.static_tm.text = "";
    } 
    
    // 网页控件
    var wb = web.view(winform.static,`\userdata`);
    var xls_data = null; 
    var video_data = null; 
    var start_flag = true; 
    var wb_hwnd = null; 
    
    // 是否离开的弹窗
    function checkExit(){
        var hwnd = winex.findEx(,,"Chrome\_WidgetWin\_\x+","是否离开网站")
        if(hwnd){
            winex.key.click(hwnd,"ENTER") 
        }   
    }
    
    // 是否离开的弹窗
    function checkMap(){
        var hwnd = winex.findEx(,,"Chrome\_WidgetWin\_\x+","")
        if(hwnd){
            winex.key.click(hwnd,"ENTER") 
        }   
    }
    
    // 浏览器窗口里面找窗口句柄,然后操作
    function getWdHwnd(){
        if(not wb_hwnd){
            checkMap();
            wb_hwnd = winex.findEx(winform.static.hwnd,,"Chrome\_RenderWidgetHostHWND","Chrome Legacy Window");
        }
        return wb_hwnd; 
    }
    
    function checkDialog(){
        /*
        if(xls_data == null or #xls_data == 0){
            winform.edit_log.print("excel数据已发布完");
            return ; 
        }
        if(video_data == null or #video_data ==0 ){
            winform.edit_log.print("视频已发布完");
            return ; 
        }*/
        
        hwnd,hwnd_button,t_id,p_id = winex.wait(,"打开","#32770","Button")
        if(hwnd){
            winform.edit_log.print(hwnd,hwnd_button,t_id,p_id)
        
            hwnd_edit = winex.findEx(hwnd,,"Edit","")
            sleep(100);
            winex.mouse.click(hwnd_edit,32,18)
            winform.edit_log.print(hwnd_edit)
            sleep(100);
            var txt = table.pop(video_data,1);
            if(txt && #txt > 0){
                txt = winform.edit_video.text + "\" + txt;
                winform.edit_log.print(txt);
                winex.sayIme(txt,hwnd_edit)
                sleep(100);
                winform.edit_log.print(hwnd_button)
                winex.key.click(hwnd_button,"ENTER") 
            }else {
                winform.edit_log.print("没有更多上传视频");
            }
            return true; 
        }
        sleep(500);
        var hwnd = winex.findEx(,,"#32770","打开");
        retun (hwnd == null);
    }
    
    
    
    // 异步调用
    wb.external = {
        uploadVideo = function(){   
            checkDialog();      
        };
        sendMsg = function(data,flag){
            if(start_flag==false){
                winform.edit_log.print("停止");
                return ; 
            }   
            
            x,y = data["x"]+data["width"]-5,data["y"]+data["height"]-5;     
            winform.edit_log.print(x,y);
            // 点击输入框位置
            winex.mouse.clickDB(getWdHwnd(),x,y);
            // 输入文案
            if(#winform.edit_tips.text > 0 and flag){
                sleep(500);
                winex.say(winform.edit_tips.text,hwnd);
            }       
            handleMsg();        
        };
        nextMsg = function(data){
            if(start_flag==false){
                winform.edit_log.print("停止");
                return ; 
            }
            winform.edit_log.print("成功:" + data);
            // 成功,可以接续下一个
            handleMsg();
        };
        exitMsg = function(data){
            winform.edit_log.print("成功:" + data);
            winform.edit_log.print("文字超长,回删");
            // 数量大于500,说明可以停止   
            winex.key.combine(getWdHwnd(),"CTRL","Z");
            winex.key.combine(getWdHwnd(),"CTRL","Z");
            if(start_flag==false){
                winform.edit_log.print("停止");
                return ; 
            }
            commitMsg();
        };
        errorMsg = function(){
            winform.edit_log.print("用户未找到");
            // 没有找到id,下一个
            winex.key.combine(getWdHwnd(),"CTRL","Z");
            if(start_flag==false){
                winform.edit_log.print("停止");
                return ; 
            }
            handleMsg();
        };
        submitMsg = function(data){
            if(start_flag==false){
                winform.edit_log.print("停止");
                return ; 
            }
            winform.edit_log.print("发布");
            sleep(500);
            
            x,y,cx,cy = winform.static.getPos(true);
            
            x,y = x+data["x"]+data["width"]/2,y+data["y"]+data["height"]/2;
            
            winform.edit_log.print(x,y);
            mouse.click(x,y,true)
            //winex.mouse.clickDB(getWdHwnd(),x,y);
            sleep(5000);
            // 进行下一页
            wb.go("https://creator.douyin.com/creator-micro/content/upload");
            //checkExit();
        };
        
    }
    
    // 网页加载监听
    wb.onDocumentInit = function(url){
        winform.edit_log.print(url);
        if(url="https://creator.douyin.com/creator-micro/content/upload"){
            
            // 用法三:异步等待参数@1指定CSS选择器的节点,回调 Javascript 代码
            // 第一个页面,上传视频
            wb.waitEle("label",`
                document.querySelector("label").click();
                // 这里至关重要,文件弹框跟uploadVideo方法里面等待阻塞,导致可能模拟操作失败。因此这里异步等待弹框先出来。
                setTimeout(function () {
                    aardio.uploadVideo();
                },3000);
            `);
            
            // 第二个页面,发送文本
            wb.waitEle("div#root div.editor-kit-root-container",`
                setTimeout(function () {
                    aardio.sendMsg(document.querySelector("div#root div.editor-kit-root-container > div > div").getBoundingClientRect(),true);
                },1000);
            `);
            
            // 发布后,取消同步到西瓜
            wb.waitEle("button.semi-button.semi-button-tertiary.semi-button-light > span.semi-button-content",`
                document.evaluate("//span[@class='semi-button-content' and text()='暂不同步']",document).iterateNext().click();
            `);
        }
    }
    
    // 读取excel数据
    function readExcel(xlsPath,sheetName=1){
        var excel,err = com.excel();
        excel.alerts = false;
        
        var book = excel.Open(xlsPath);
     
        var sheet = book.Sheets(sheetName);
        var count = sheet.UsedRange.Rows.Count;
        var res = {}; 
        for(i=2;count;1){
            table.push(res,sheet.Cells(i,2).Text);
        }
        excel.Quit();
        return res; 
    }
    
    // 锁定控件
    function clockCtrl(flag){
        winform.edit_sn.text = myplu.vip.keyCode();
        winform.edit_xls.disabled = flag;
        winform.edit_video.disabled = flag;
        winform.edit_sleep.disabled = flag;
        winform.edit_tips.disabled = flag;
        winform.btn_xls.disabled = flag;
        winform.btn_video.disabled = flag;
        winform.button_start.disabled = flag;
        winform.button_clean.disabled = flag;
        if(flag){
            timer.enable();
        }else{
            timer.disable();
        }
    }
    
    // 检测时间
    function checkVip(){
        var res = false; 
        if(winform.edit_vip.text == ""){
            win.msgbox("请联系运营申请激活码!","运行提示");
            clockCtrl(true);
            return res; 
        }
        try{
            var tm = myplu.vip.decode("xxxxx",winform.edit_vip.text);
            if(tm){
                if(time.now().diffsecond(tm) > 0){
                    clockCtrl(true);
                    winform.static_tm.text=tostring(tm,"%Y-%m-%d %H:%M:%S","chs");
                    winform.edit_log.print("激活码已过期");
                }else {
                    clockCtrl(false);
                    winform.static_tm.text=tostring(tm,"%Y-%m-%d %H:%M:%S","chs");
                    winform.edit_log.print("已激活");
                    res = true; 
                }
            }else {
                clockCtrl(true);
                winform.edit_log.print("激活失败");
            }
        }
        catch(e){
            clockCtrl(true);
            win.msgbox("请输入有效的激活码!","运行提示");    
        }   
        return res; 
    }
    
    // 模拟发送
    function handleMsg(){
        var res;
        do{ 
            // 成功,可以接续下一个
            if(#xls_data > 0){
                res = addUser();
            }else {
                commitMsg();
                res = true;
            }
        }while(res == false)
    }
    
    
    // 添加配置操作
    function addUser(){
        var userId = table.pop(xls_data,1);             
        if(userId and #userId>0){
            winform.edit_log.print(userId);
            sleep(500)
            winex.say("@" + userId) 
            sleep(tonumber(winform.edit_sleep.text))        
            wb.doScript(`
                (function(){
                    var node = document.evaluate('.//span[contains(string(),"抖音号 ` + userId + `")]',document).iterateNext();
                    if(node){
                        node.click();
                        // 之后执行
                        setTimeout(function () {
                            var psize = document.querySelector("#root div.editor-kit-editor-container > div:nth-child(2)").innerText.match(/\d+/ig);
                            if(parseInt(psize[0]) < parseInt(psize[1])){
                                // 说明可以继续填写
                                aardio.nextMsg(node.innerText);
                            }else{
                                // 说明不能继续填写
                                aardio.exitMsg(node.innerText);
                            }
                        }, 200)
                    }else{
                        // 不存在,说明失败
                        aardio.errorMsg();
                    } 
                })();
                `,function(result,err){
                    
            }); 
            return true;
        }else{
            return false; 
        }    
    }
    
    // 发布动作
    function commitMsg(){
        wb.doScript(`
            (function(){
                document.evaluate("//label[span/text()='不允许']/input[@type='checkbox']",document).iterateNext().click();
                document.evaluate("//button[text()='发布']",document).iterateNext().scrollIntoView();
                setTimeout(function () {
                    aardio.submitMsg(document.evaluate("//button[text()='发布']",document).iterateNext().getBoundingClientRect());
                }, 1000)
            })();
            `,function(result,err){
                
        }); 
    }
    
    // 开始按钮
    winform.button_start.oncommand = function(id,event){
        if(winform.button_start.text == "停止"){
            start_flag = false;     
            winform.button_start.text = "继续";
            return ;
        }
        
        var res = checkVip();
        if(res == null){
            return ; 
        }
        // 检查excel
        if(winform.edit_xls.text == ""){
            winform.edit_log.print("请选择Excel文件");
            winform.btn_xls.oncommand();
            return;
        }elseif(io.exist(winform.edit_xls.text) == false) {
            winform.edit_log.print("Excel文件不存在,重新选择!");
            winform.btn_xls.oncommand();
            return;
        }
        // 检查视频
        if(winform.edit_video.text == ""){
            winform.edit_log.print("请选择要上传视频的目录");
            winform.btn_video.oncommand();
            return;
        }elseif(io.exist(winform.edit_video.text) == false) {       
            winform.edit_log.print("视频目录不存在,重新选择!");
            winform.btn_video.oncommand();
            return;
        }
        
        // 构造excel数据
        if(xls_data == null){
            winform.edit_log.print("读取excel数据");
            xls_data = readExcel(winform.edit_xls.text);
            table.reverse(xls_data);
        }
        
        // 查找视频文件名
        if(video_data == null){
            winform.edit_log.print("扫描上传视频文件");
            video_data = fsys.list(winform.edit_video.text)
        }
        
        winform.button_start.text = "停止";
        if(start_flag){     
            winform.edit_log.print("开始");
            winform.edit_log.print("打开抖音上传页面");
            wb.go("https://creator.douyin.com/creator-micro/content/upload");
        }else {
            start_flag = true;
            winform.edit_log.print("继续");       
            // 第二个页面,发送文本
            wb.waitEle("div#root div.editor-kit-root-container",`
                aardio.sendMsg(document.querySelector("div#root div.editor-kit-root-container > div > div").getBoundingClientRect(),false);
            `);
        }       
    }
    
    // 清空按钮
    winform.button_clean.oncommand = function(id,event){
        winform.edit_log.text = "";
    }
    
    // 视频目录
    import fsys.dlg.dir;
    winform.btn_video.oncommand = function(id,event){
        var path = fsys.dlg.dir(,winform,'请选择视频目录')
        if(path){
            winform.edit_video.text = path;
            video_data = null;
        }   
        // 保持配置
        config.saveAll();
    }
    winform.btn_video.skin({
        color={
            active=0xFF00FF00;
            default=0xFF3C3C3C;
            disabled=0xFF6D6D6D;
            hover=0xFFFF0000
        }
    })
    
    // excel 文件
    import fsys.dlg;
    winform.btn_xls.oncommand = function(id,event){
        var path = fsys.dlg.open('Excel文件|*.elx;*.xlsx||',,,winform);
        if(path){
            winform.edit_xls.text = path;
            xls_data = null;
        }
        // 保持配置
        config.saveAll();
    }
    winform.btn_xls.skin({
        color={
            active=0xFF00FF00;
            default=0xFF3C3C3C;
            disabled=0xFF6D6D6D;
            hover=0xFFFF0000
        }
    })
    
    winform.show();
    
    // 话术编辑后保存
    winform.edit_tips.onFocusLost = function(id,event){ 
        // 保持配置
        config.saveAll();
    }
    
    // 间隔时间
    winform.edit_sleep.onFocusLost = function(id,event){
        // 保持配置
        config.saveAll();
    }
    // 清空日志框
    winform.edit_log.text = "请自行登录抖音账号";
    // 打开抖音
    wb.go("https://www.douyin.com/");
    
    winform.edit_vip.onFocusLost = function(id,event){
        checkVip();
    }
    
    checkVip();
    checkExit();
    
    win.loopMessage();
    

    相关文章

      网友评论

        本文标题:webview2抖音视频自动发布

        本文链接:https://www.haomeiwen.com/subject/hfbzudtx.html