背景
研究下 Python+Selenium 自動化測試框架泥栖,簡單實(shí)現(xiàn) Mac 下自動化批量上傳視頻西瓜視頻并發(fā)布,分享給需要的同學(xué)(未做過多的異常處理)。
腳本實(shí)現(xiàn)
- 首先通過手工手機(jī)號登錄阴绢,保存西瓜視頻網(wǎng)站的 cookie 文件
- 之后加載 cookie 內(nèi)容,使用腳本批量上傳視頻艰躺,保存到草稿(也可自動發(fā)布呻袭,為了二次編輯,如修改封面)
- 最后通過遍歷視頻草稿列表腺兴,來進(jìn)行草稿視頻發(fā)布
PS: 同一天上傳或發(fā)布視頻太多時左电,會被西瓜視頻限流。
安裝依賴
# 安裝依賴
$ pip install selenium PyUserInput pyperclip
# 安裝 chromedriver
$ brew install chromedriver
腳本內(nèi)容
#!/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 西瓜視頻自動上傳視頻及發(fā)布草稿
"""
def __init__(self):
"""
初始化页响,打開瀏覽器
"""
self.driver = webdriver.Chrome()
def save_cookies(self, cookies_file_name):
"""
保存 cookies
cookies_file_name: cookies 文件名稱
"""
# 預(yù)留 20 秒篓足,來進(jìn)行手工登錄
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")
# 點(diǎn)擊上傳
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)
# 復(fù)制視頻文件路徑
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)
# 設(shè)置轉(zhuǎn)載選項
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()
# 循環(huán)判斷視頻上傳成功,不成功等待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("循環(huán)等待視頻上傳成功,等待10秒")
time.sleep(10)
# 設(shè)置視頻封面
self.driver.find_element_by_class_name("m-xigua-upload").click()
print('點(diǎn)擊-上傳封面')
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]')
# 視頻封面解析失敗處理盼玄,循環(huán)刷新
if reload != '':
print('視頻封面解析失敗處理贴彼,開始循環(huán)刷新')
while XiGua.is_exist_element_by_xpath(self,
'/html/body/div[3]/div/div[2]/div/div[1]/div/div/div/div[2]'):
# 點(diǎn)擊循環(huán)
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('點(diǎn)擊-封面下一步')
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('點(diǎn)擊-封面完成裁剪')
else:
print('封面無需裁剪')
except Exception as e:
print('裁剪封面出現(xiàn)異常:%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('點(diǎn)擊-封面確定')
time.sleep(1)
# 再次確定
self.driver.find_element_by_xpath('/html/body/div[4]/div/div[2]/div/div[2]/button[2]').click()
print('點(diǎn)擊-封面再次確定')
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('點(diǎn)擊-保存草稿')
# 移動滾動條到底部
js = "window.scrollTo(0,document.body.scrollHeight)"
self.driver.execute_script(js)
# 移動到 存草稿 按鈕點(diǎn)擊
action.move_to_element(draft_element).click().perform()
def close(self):
"""
關(guān)閉瀏覽器
"""
self.driver.close()
def batch_upload(self, videos_dir_path):
"""
批量上傳視頻
videos_dir_path: 上傳視頻存儲路徑
"""
files = os.listdir(videos_dir_path)
# 降序排序上傳,草稿發(fā)布時童番,視頻序號則為順序
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)
# 發(fā)布完成后青灼,移到到備份目錄
shutil.move(src, dst)
def videos_release(self):
"""
草稿視頻發(fā)布
"""
self.driver.get("https://studio.ixigua.com/content")
time.sleep(2)
# 點(diǎn)擊草稿導(dǎo)航
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('點(diǎn)擊-草稿導(dǎo)航')
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()
# 循環(huán)發(fā)布草稿,每次都發(fā)布第一個
for i in range(1, 99999):
# 草稿列表為空杂拨,退出
if draft_elements == '':
print('草稿發(fā)布完成专普,總共:%s' % str(i))
XiGua.close(self)
sys.exit()
print('當(dāng)前發(fā)布數(shù)量 %s, 發(fā)布視頻: %s' % (str(i), draft_elements[0].text))
# 發(fā)布草稿第一個視頻
draft_elements[0].click()
time.sleep(3)
# 立即發(fā)布
element2 = WebDriverWait(self.driver, 30).until(
lambda x: x.find_element_by_xpath('//button[contains(text(), "發(fā)布")]')
)
element2.click()
print('點(diǎn)擊-視頻發(fā)布')
# 判斷是否發(fā)布失敗弹沽,如標(biāo)題超長
try:
# 錯誤處理
if XiGua.is_exist_element_by_xpath(self, '/html/body/div[3]/div/div/div/span'):
print('發(fā)布出現(xiàn)錯誤檀夹,退出,請檢查錯誤策橘,如標(biāo)題超長等')
sys.exit()
except Exception as e:
print('草稿發(fā)布異常:%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()
# 立即發(fā)布
cover_publish_element = WebDriverWait(self.driver, 30).until(
lambda x: x.find_element_by_xpath('//button[contains(text(), "發(fā)布")]')
)
cover_publish_element.click()
except Exception as e:
print('封面分辨率低出現(xiàn)異常:%s' % e)
pass
# 點(diǎn)擊草稿
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):
"""
西瓜視頻發(fā)布草稿
base_url: 西瓜視頻網(wǎng)站
cookies_file_path: 西瓜視頻 cookies 文件路徑
"""
self.driver.get(base_url)
# 加載 cookies
XiGua.load_cookies(self, cookies_file_path)
# 草稿發(fā)布視頻
XiGua.videos_release(self)
# 關(guān)閉瀏覽器
XiGua.close(self)
def xigua_batch_upload(self, base_url, cookies_file_path, videos_dir_path):
"""
西瓜視頻批量發(fā)布視頻
base_url: 西瓜視頻網(wǎng)站
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):
"""
保存網(wǎng)站 cookie
base_url: 網(wǎng)站地址
cookies_file_path: 網(wǎng)站 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. 批量發(fā)布草稿
# xi_gua.xigua_videos_release(base_url, xigua_cookies)
微信公眾號:daodaotest