Mac 下 Python+Selenium 自动上传西瓜视频

背景

研究下 Python+Selenium 自动化测试框架,简单实现 Mac 下自动化批量上传视频西瓜视频并发布,分享给需要的同学(未做过多的异常处理)。

脚本实现

首先通过手工手机号登录,保存西瓜视频网站的 cookie 文件
之后加载 cookie 内容,使用脚本批量上传视频,保存到草稿(也可自动发布,为了二次编辑,如修改封面)
最后通过遍历视频草稿列表,来进行草稿视频发布,PS: 同一天上传或发布视频太多时,会被西瓜视频限流。

安装依赖

# 安装依赖
        保存网站 cookie

# 安装 chromedriver
$ brew install chromedriver

脚本内容

#!/usr/bin/python
# -*- coding: utf-8 -*-
import time
import json
import os
import shutil
import sys

from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver import ActionChains
from pykeyboard import PyKeyboard
from pymouse import PyMouse
import pyperclip

class XiGua:
    """
    Mac 西瓜视频自动上传视频及发布草稿
    """
    def __init__(self):
        """
        初始化,打开浏览器
        """
        self.driver = webdriver.Chrome()

    def save_cookies(self, cookies_file_name):
        """
        保存 cookies
        cookies_file_name: cookies 文件名称
        """
        # 预留 20 秒,来进行手工登录
        time.sleep(20)
        # 登录成功后,保存 cookies 文件
        with open(cookies_file_name, 'w') as cookies_file:
            cookies_file.write(json.dumps(self.driver.get_cookies()))

    def load_cookies(self, cookies_file_name):
        """
        加载 cookie
        cookies_file_name: cookies 文件名称
        """
        # 加载 cookies 文件
        with open(cookies_file_name, 'r') as cookies_file:
            cookies_list = json.load(cookies_file)
            for cookie in cookies_list:
                if 'expiry' in cookie:
                    del cookie['expiry']
                self.driver.add_cookie(cookie)
        # 加载 cookie 后,刷新页面生效
        self.driver.refresh()

    def is_exist_element_by_xpath(self, xpath):
        """
        判断元素是否存在
        """
        flag = True
        try:
            self.driver.find_element_by_xpath(xpath)
            return flag
        except Exception as e:
            flag = False
            print("xpath: [%s] 的元素不存在,错误:%s" % xpath, e)
            return flag

    def upload_video(self, video_file_path):
        """
        上传视频
        video_file_path: 上传视频路径
        """
        # 打开上传视频页面
        self.driver.get("https://studio.ixigua.com/upload?from=post_article")
        # 点击上传
        self.driver.find_element_by_class_name("byte-upload-trigger-drag").click()
        time.sleep(5)
        # 选择视频文件
        k = PyKeyboard()
        m = PyMouse()
        # 打开
        k.press_keys(['Command', 'Shift', 'G'])
        x_dim, y_dim = m.screen_size()
        k.press_keys(['Shift'])
        m.click(x_dim // 2, y_dim // 2, 1)
        # 复制视频文件路径
        pyperclip.copy(video_file_path)
        # 粘贴
        k.press_keys(['Command', 'V'])
        time.sleep(2)
        k.press_key('Return')
        time.sleep(2)
        k.press_key('Return')
        time.sleep(2)
        # 设置转载选项
        self.driver.find_element_by_xpath(
            '//*[@id="js-video-list-content"]/div/div[2]/div[4]/div[2]/div/div/label[2]/span/span').click()
        time.sleep(1)
        # 同步到抖音
        # self.driver.find_element_by_class_name("byte-checkbox-mask").click()
        # 循环判断视频上传成功,不成功等待10秒后,再次判断,直到成功
        while '上传成功' not in self.driver.find_element_by_xpath(
                '//*[@id="js-video-list-content"]/div/div[1]/div[1]/div[2]/div[2]').text:
            print("循环等待视频上传成功,等待10秒")
            time.sleep(10)
        # 设置视频封面
        self.driver.find_element_by_class_name("m-xigua-upload").click()
        print('点击-上传封面')
        time.sleep(5)
        try:
            reload = self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div[1]/div/div/div/div[2]')
            # 视频封面解析失败处理,循环刷新
            if reload != '':
                print('视频封面解析失败处理,开始循环刷新')
                while XiGua.is_exist_element_by_xpath(self,
                                                      '/html/body/div[3]/div/div[2]/div/div[1]/div/div/div/div[2]'):
                    # 点击循环
                    self.driver.find_element_by_xpath(
                        '/html/body/div[3]/div/div[2]/div/div[1]/div/div/div/div[2]').click()
                    print('刷新失败后,等待5秒,再次刷新')
                    time.sleep(5)
                # 选择第一个图片
                img = self.driver.find_element_by_xpath('/html/body/div[3]/div/div[2]/div/div[1]/div/div/div[1]/img')
                img.click()
        except Exception as e:
            print('封面解析正常,无需刷新')
            pass
        # 下一步
        cover_next_element = WebDriverWait(self.driver, 30).until(
            lambda x: x.find_element_by_xpath(
                '/html/body/div[3]/div/div[2]/div/div[2]/div')
        )
        cover_next_element.click()
        print('点击-封面下一步')
        try:
            # 完成裁剪
            cover_crop_element = WebDriverWait(self.driver, 30).until(
                lambda x: x.find_element_by_xpath(
                    '//*[@id="tc-ie-base-content"]/div[2]/div[2]/div[2]/div/div[2]/div/div/div[2]')
            )
            if cover_crop_element != '':
                cover_crop_element.click()
                print('点击-封面完成裁剪')
            else:
                print('封面无需裁剪')
        except Exception as e:
            print('裁剪封面出现异常:%s' % e)
            pass
        time.sleep(5)
        # 确定
        self.driver.find_element_by_xpath('//*[@id="tc-ie-base-content"]/div[2]/div[2]/div[3]/div[3]/button[2]').click()
        print('点击-封面确定')
        time.sleep(1)
        # 再次确定
        self.driver.find_element_by_xpath('/html/body/div[4]/div/div[2]/div/div[2]/button[2]').click()
        print('点击-封面再次确定')
        time.sleep(5)
        # 存草稿
        draft_element = WebDriverWait(self.driver, 30).until(
            lambda x: x.find_element_by_xpath('//*[@id="js-submit-draft-0"]/button')
        )
        action = ActionChains(self.driver)
        print('点击-保存草稿')
        # 移动滚动条到底部
        js = "window.scrollTo(0,document.body.scrollHeight)"
        self.driver.execute_script(js)
        # 移动到 存草稿 按钮点击
        action.move_to_element(draft_element).click().perform()

    def close(self):
        """
        关闭浏览器
        """
        self.driver.close()

    def batch_upload(self, videos_dir_path):
        """
        批量上传视频
        videos_dir_path: 上传视频存储路径
        """
        files = os.listdir(videos_dir_path)
        # 降序排序上传,草稿发布时,视频序号则为顺序
        files.sort(reverse=True)
        # 批量上传视频
        for file in files:
            if os.path.splitext(file)[1] == '.mp4':
                full_file_path = os.path.join(videos_dir_path, os.path.splitext(file)[0])
                print("==开始上传视频:%s" % full_file_path)
                self.upload_video(full_file_path)
                src = os.path.join(videos_dir_path, file)
                dst = os.path.join(videos_dir_path, 'bak', file)
                # 发布完成后,移到到备份目录
                shutil.move(src, dst)

    def videos_release(self):
        """
        草稿视频发布
        """
        self.driver.get("https://studio.ixigua.com/content")
        time.sleep(2)
        # 点击草稿导航
        draft_navigation_element = WebDriverWait(self.driver, 30).until(
            lambda x: x.find_element_by_xpath('//*[@id="app"]/div/section/div/div[1]/ul/li[3]')
        )
        draft_navigation_element.click()
        print('点击-草稿导航')
        time.sleep(2)
        # 草稿列表
        draft_elements = self.driver.find_elements_by_class_name('content-card__title ')
        # 草稿列表为空,则退出
        if len(draft_elements) == 0:
            print("草稿列表为空")
            XiGua.close(self)
            sys.exit()
        # 循环发布草稿,每次都发布第一个
        for i in range(1, 99999):
            # 草稿列表为空,退出
            if draft_elements == '':
                print('草稿发布完成,总共:%s' % str(i))
                XiGua.close(self)
                sys.exit()
            print('当前发布数量 %s, 发布视频: %s' % (str(i), draft_elements[0].text))
            # 发布草稿第一个视频
            draft_elements[0].click()
            time.sleep(3)
            # 立即发布
            element2 = WebDriverWait(self.driver, 30).until(
                lambda x: x.find_element_by_xpath('//button[contains(text(), "发布")]')
            )
            element2.click()
            print('点击-视频发布')
            # 判断是否发布失败,如标题超长
            try:
                # 错误处理
                if XiGua.is_exist_element_by_xpath(self, '/html/body/div[3]/div/div/div/span'):
                    print('发布出现错误,退出,请检查错误,如标题超长等')
                    sys.exit()
            except Exception as e:
                print('草稿发布异常:%s' % e)
                pass
            # 处理封面分辨率低提示
            try:
                # 封面分辨率低
                cover_cancel_element = self.driver.find_element_by_xpath('//div[contains(text(), "取消")]')
                print('封面分辨率低处理,直接取消')
                # 错误处理
                if cover_cancel_element != '':
                    print('取消封面分辨率低')
                    cover_cancel_element.click()
                    # 立即发布
                    cover_publish_element = WebDriverWait(self.driver, 30).until(
                        lambda x: x.find_element_by_xpath('//button[contains(text(), "发布")]')
                    )
                    cover_publish_element.click()
            except Exception as e:
                print('封面分辨率低出现异常:%s' % e)
                pass
            # 点击草稿
            draft_publish_element = WebDriverWait(self.driver, 30).until(
                lambda x: x.find_element_by_xpath('//*[@id="app"]/div/section/div/div[1]/ul/li[3]')
            )
            draft_publish_element.click()
            time.sleep(2)
            print('重新获取草稿列表')
            draft_elements = self.driver.find_elements_by_class_name('content-card__title ')
            print(draft_elements)

    def xigua_videos_release(self, base_url, cookies_file_path):
        """
        西瓜视频发布草稿
        base_url: 西瓜视频网站
        cookies_file_path: 西瓜视频 cookies 文件路径
        """
        self.driver.get(base_url)
        # 加载 cookies
        XiGua.load_cookies(self, cookies_file_path)
        # 草稿发布视频
        XiGua.videos_release(self)
        # 关闭浏览器
        XiGua.close(self)

    def xigua_batch_upload(self, base_url, cookies_file_path, videos_dir_path):
        """
        西瓜视频批量发布视频
        base_url: 西瓜视频网站
        cookies_file_path: 西瓜视频 cookies 文件路径
        videos_dir_path: 上传视频存储路径
        """
        self.driver.get(base_url)
        XiGua.load_cookies(self, cookies_file_path)
        XiGua.batch_upload(self, videos_dir_path)
        XiGua.close(self)

    def xigua_save_cookies(self, base_url, cookies_file_path):
        """
        保存网站 cookie
        base_url: 网站地址
        cookies_file_path: 网站 cookies 文件路径
        """
        self.driver.get(base_url)
        # 保存 cookies
        XiGua.save_cookies(self, cookies_file_path)
        XiGua.close(self)

if __name__ == '__main__':
    xi_gua = XiGua()
    # 西瓜视频
    base_url = 'https://www.ixigua.com/'
    xigua_cookies = '/tmp/xigua_update_video/xigua_cookies.txt'
    videos_dir_path = '/tmp/rm'
    ## 1. 保存 cookie
    # xi_gua.xigua_save_cookies(base_url, 'xigua_cookies.txt')
    ## 2. 批量上传
    xi_gua.xigua_batch_upload(base_url, xigua_cookies, videos_dir_path)
    ## 3. 批量发布草稿
    # xi_gua.xigua_videos_release(base_url, xigua_cookies)

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你! 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/411239.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于java在线调查表单系统

基于java在线调查表单系统 一、演示效果二、特性汇总三、下载链接 一、演示效果 二、特性汇总 多种技术方案,满足不同的技术选型需求完善的浏览器兼容、保证传统客户也能正常使用部署简单,一行命令完成部署更新方便,直接替换原安装文件不用担…

通过二叉树例题深入理解递归问题

目录 引入: 例1:二叉树的前序遍历: 例2: N叉树的前序遍历: 例3:二叉树的最大深度: 例4:二叉树的最小深度 例5:N叉树的最大深度: 例6:左叶子…

基于Springboot的旅游网管理系统设计与实现(有报告)。Javaee项目,springboot项目。

演示视频: 基于Springboot的旅游网管理系统设计与实现(有报告)。Javaee项目,springboot项目。 项目介绍: 采用M(model)V(view)C(controller)三层…

ui设计:利用即使设计设计出漂亮样式

目录 一、基本操作 二、具体介绍 6-1 填充图片 6-2 填充色 6-3 图标 右边栏基础设置 右边栏导出​编辑 一、基本操作 二、具体介绍 6-1 填充图片 选择其一图片填充 6-2 填充色 6-3 图标 右边栏基础设置 右边栏导出

C++17之折叠表达式

相关文章系列 深入理解可变参数(va_list、std::initializer_list和可变参数模版) 目录 1.介绍 2.应用 2.1.使用折叠表达式 2.2.支持的运算符 2.3.使用折叠处理类型 3.总结 1.介绍 折叠表达式是C17新引进的语法特性。使用折叠表达式可以简化对C11中引入的参数包的处理&…

自定义el-upload 上传文件

前言 最近在做一个文件上传的功能&#xff0c;后端接口写好了、发现前端上传文件的页面不会写……&#xff08;我很笨的&#xff09;然后我就找啊找发现element有个组件是<el-upload/>能直接上传文件。我就想直接用拿来改改改成自己想要的&#xff0c;可是就是这样我花了…

【C++】拷贝构造函数(深拷贝和浅拷贝)

使用场景 在C类中&#xff0c;我们在类的成员变量内定义了一个指针。这时我们需要去创建它的拷贝构造函数&#xff0c;否则编译器会为这个类创建默认的拷贝构造函数&#xff0c;而默认拷贝构造函数会导致浅拷贝问题&#xff1b;浅拷贝可能会会导致内存泄漏问题&#xff0c;也可…

MATLAB Function转C代码实战

文章目录 前言1. 准备工作2. 使用MATLAB Coder2.1 确定输入输出的类型2.2 MATLAB Coder过程 3. 代码调整和优化4. 编译和测试5. 性能分析和优化结语 前言 在科学与工程领域&#xff0c;MATLAB&#xff08;Matrix Laboratory&#xff09;是一种广泛使用的高级技术计算软件&…

一个Post请求入门NestJS的路由与控制器

​ NestJS的控制器 控制器负责处理传入请求并向客户端返回响应。 控制器的目的是接收应用的特定请求。路由机制控制哪个控制器接收哪些请求。 通常&#xff0c;每个控制器都有不止一条路由&#xff0c;不同的路由可以执行不同的操作。 在使用了脚手架的项目中&#xff0c;我…

【激光SLAM】基于图优化的激光SLAM 方法(Grid-based)

文章目录 Graph-based SLAM数学概念 非线性最小二乘(Non-Linear Least Square)解决的问题误差函数线性化流程 非线性最小二乘在SLAM中的应用图的构建&#xff08;SLAM前端&#xff09;误差函数误差函数的线性化固定坐标系构建线性系统求解 Cartographer介绍 Graph-based SLAM …

如何在本地部署密码管理软件bitwarden并结合cpolar实现远程同步

文章目录 1. 拉取Bitwarden镜像2. 运行Bitwarden镜像3. 本地访问4. 群晖安装Cpolar5. 配置公网地址6. 公网访问Bitwarden7. 固定公网地址8. 浏览器密码托管设置 Bitwarden是一个密码管理器应用程序&#xff0c;适用于在多个设备和浏览器之间同步密码。自建密码管理软件bitwarde…

上门服务系统|上门服务小程序|上门服务软件开发

随着移动互联网技术的普及&#xff0c;上门服务小程序系统成为现代企业数字化转型的关键一环。这一系统为消费者提供了更加便捷、高效以及个性化的服务体验&#xff0c;同时也为企业带来了更广阔的商业机会。让我们来看看上门服务小程序系统的优势和功能。 首先&#xff0c;上门…

数据安全治理实践路线(下)

数据安全运营阶段通过不断适配业务环境和风险管理需求&#xff0c;持续优化安全策略措施&#xff0c;强化整个数据安全治理体系的有效运转。 数据安全运营 1. 风险防范 数据安全治理的目标之一是降低数据安全风险&#xff0c;因此建立有效的风险防范手段&#xff0c;对于预防…

使用Docker部署MinIO并结合内网穿透实现远程访问本地数据

文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器&#xff0c;可以在各种环境中运行&#xff0c;例如本地、Docker容器、Kubernetes集群等。它兼…

Redis高可用三主三从集群部署

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容使用宝塔面板搭建集群规划配置验证 使用docker搭建使用脚本搭建&#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博…

【JS】事件绑定方法自带一个形参e“function(e)”,what is e?

在学习js的时候 我跳过了一部分章节的内容&#xff0c;导致现在学习react的时候很多内容都不知所措&#xff0c;因为这些教程都是建立在它认为你js所有内容都掌握的前提下&#xff0c;当然这是我自身的原因。需要反省。 下面是正题&#xff1a; 我们知道js有很多事件&#…

Linux设备模型(五) - uevent kernel实现

1. Uevent的功能 Uevent是Kobject的一部分&#xff0c;用于在Kobject状态发生改变时&#xff0c;例如增加、移除等&#xff0c;通知用户空间程序。用户空间程序收到这样的事件后&#xff0c;会做相应的处理。 该机制通常是用来支持热拔插设备的&#xff0c;例如U盘插入后&…

mac flutter 配置

下载Flutter Sdk Start building Flutter Android apps on macOS - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 下载后解压放到一个文件夹 /Users/zhiyu/Documents/gitflutter/flutter3.19.1/ 环境变量中要用到 配置 Android 开发 下载 Android Studio 和应用工具…

软件运维维保服务方案-套用模板

软件运维维保方案-套用模板 项目情况 1.1 项目背景简述项目的来源、目的和重要性。说明项目的规模、预算和预期目标。 1.2 项目现状分析当前系统/软件的运行状态、存在的问题和潜在风险。提供最近一次的维护报告或相关统计数据。服务简述 2.1 服务内容明确运维服务的具体内容&…

三、系统知识笔记-计算机系统基础知识

一、计算机系统概述 计算机系统是指用于数据管理的计算机硬件、软件及网络组成的系统。 它是按人的要求接收和存储信息&#xff0c;自动进行数据处理和计算&#xff0c;并输出结果信息的机器系统。 冯诺依曼体系计算机结构&#xff1a; 1.1计算机硬件组成 冯诺依曼计算机结…