Python+Selenium automatically uploads watermelon videos on Mac

Background

Let’s study the Python + Selenium automated testing framework, and simply implement automated batch uploading and publishing of videos on Mac, and share them with students who need them (without doing too much exception handling).

Script implementation

First log in with your manual mobile phone number and save the cookie file of the Xigua Video website.

Then load the cookie content, use a script to upload videos in batches, and save them to drafts (it can also be automatically published for secondary editing, such as modifying the cover)

Finally, the draft video is published by traversing the video draft list. PS: If too many videos are uploaded or published on the same day, the video will be limited by Xigua Video.

Installation dependencies

# Install dependencies
        Save website cookies

# Install chromedriver
$ brew install chromedriver

Script content

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

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 Xigua Video automatically uploads videos and publishes drafts
    """
    def __init__(self):
        """
        Initialize, open the browser
        """
        self.driver = webdriver.Chrome()

    def save_cookies(self, cookies_file_name):
        """
        save cookies
        cookies_file_name: cookies file name
        """
        # Reserve 20 seconds for manual login
        time.sleep(20)
        # After successful login, save the cookies file
        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):
        """
        Load cookies
        cookies_file_name: cookies file name
        """
        # Load cookies file
        with open(cookies_file_name, 'r') as cookies_file:
            cookies_list = json.load(cookies_file)
            for cookies in cookies_list:
                if 'expiry' in cookie:
                    del cookie['expiry']
                self.driver.add_cookie(cookie)
        # After loading the cookie, refresh the page to take effect.
        self.driver.refresh()

    def is_exist_element_by_xpath(self, xpath):
        """
        Determine whether the element exists
        """
        flag = True
        try:
            self.driver.find_element_by_xpath(xpath)
            return flag
        except Exception as e:
            flag=False
            print("xpath: [%s] element does not exist, error: %s" % xpath, e)
            return flag

    def upload_video(self, video_file_path):
        """
        Upload video
        video_file_path: upload video path
        """
        #Open the upload video page
        self.driver.get("https://studio.ixigua.com/upload?from=post_article")
        # Click to upload
        self.driver.find_element_by_class_name("byte-upload-trigger-drag").click()
        time.sleep(5)
        # Select video file
        k = PyKeyboard()
        m = PyMouse()
        # Open
        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)
        #Copy video file path
        pyperclip.copy(video_file_path)
        # Paste
        k.press_keys(['Command', 'V'])
        time.sleep(2)
        k.press_key('Return')
        time.sleep(2)
        k.press_key('Return')
        time.sleep(2)
        # Set reprint options
        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)
        # Sync to Douyin
        # self.driver.find_element_by_class_name("byte-checkbox-mask").click()
        # Loop to determine whether the video upload is successful. If it is not successful, wait for 10 seconds and then determine again until it is successful.
        while 'Upload successful' not in self.driver.find_element_by_xpath(
                '//*[@id="js-video-list-content"]/div/div[1]/div[1]/div[2]/div[2]').text:
            print("Loop waiting for the video to be uploaded successfully, wait 10 seconds")
            time.sleep(10)
        # Set video cover
        self.driver.find_element_by_class_name("m-xigua-upload").click()
        print('Click-upload cover')
        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]')
            # Video cover parsing failure processing, loop refresh
            if reload != '':
                print('Video cover analysis failure processing, start cycle refresh')
                while XiGua.is_exist_element_by_xpath(self,
                                                      '/html/body/div[3]/div/div[2]/div/div[1]/div/div/div/div[2]'):
                    # Click to loop
                    self.driver.find_element_by_xpath(
                        '/html/body/div[3]/div/div[2]/div/div[1]/div/div/div/div[2]').click()
                    print('After the refresh fails, wait 5 seconds and refresh again')
                    time.sleep(5)
                # Select the first image
                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('Cover parsing is normal, no need to refresh')
            pass
        # Next step
        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('Click-Cover Next')
        try:
            # Complete cropping
            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('Click-Cover completed cropping')
            else:
                print('Cover does not need to be cropped')
        except Exception as e:
            print('An exception occurred when cutting the cover: %s' % e)
            pass
        time.sleep(5)
        # Sure
        self.driver.find_element_by_xpath('//*[@id="tc-ie-base-content"]/div[2]/div[2]/div[3]/div[3]/button[2]' ).click()
        print('Click-Cover Confirm')
        time.sleep(1)
        # Confirm again
        self.driver.find_element_by_xpath('/html/body/div[4]/div/div[2]/div/div[2]/button[2]').click()
        print('Click-confirm the cover again')
        time.sleep(5)
        # Save draft
        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('Click-Save Draft')
        # Move the scroll bar to the bottom
        js = "window.scrollTo(0,document.body.scrollHeight)"
        self.driver.execute_script(js)
        # Move to Save Draft button click
        action.move_to_element(draft_element).click().perform()

    def close(self):
        """
        Close browser
        """
        self.driver.close()

    def batch_upload(self, videos_dir_path):
        """
        Upload videos in batches
        videos_dir_path: upload video storage path
        """
        files = os.listdir(videos_dir_path)
        # Sort the upload in descending order. When the draft is published, the video serial number is in order.
        files.sort(reverse=True)
        #Batch upload videos
        for file in files:
            if os.path.slitext(file)[1] == '.mp4':
                full_file_path = os.path.join(videos_dir_path, os.path.splitext(file)[0])
                print("==Start uploading video: %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)
                # After publishing is completed, move to the backup directory
                shutil.move(src, dst)

    def videos_release(self):
        """
        Draft video release
        """
        self.driver.get("https://studio.ixigua.com/content")
        time.sleep(2)
        # Click on draft navigation
        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('Click-Draft Navigation')
        time.sleep(2)
        # Draft list
        draft_elements = self.driver.find_elements_by_class_name('content-card__title ')
        # If the draft list is empty, exit
        if len(draft_elements) == 0:
            print("Draft list is empty")
            XiGua.close(self)
            sys.exit()
        # Publish drafts in a loop, publishing the first one each time
        for i in range(1, 99999):
            # The draft list is empty, exit
            if draft_elements == '':
                print('Draft publishing completed, total: %s' % str(i))
                XiGua.close(self)
                sys.exit()
            print('Current release quantity %s, release video: %s' % (str(i), draft_elements[0].text))
            # Publish the first video of the draft
            draft_elements[0].click()
            time.sleep(3)
            # Publish now
            element2 = WebDriverWait(self.driver, 30).until(
                lambda x: x.find_element_by_xpath('//button[contains(text(), "Publish")]')
            )
            element2.click()
            print('Click-Video Publish')
            # Determine whether publishing failed, such as the title is too long
            try:
                # Error handling
                if XiGua.is_exist_element_by_xpath(self, '/html/body/div[3]/div/div/div/span'):
                    print('An error occurred in publishing, exit, please check for errors, such as the title is too long, etc.')
                    sys.exit()
            except Exception as e:
                print('Draft publishing exception: %s' % e)
                pass
            # Handle low cover resolution prompts
            try:
                # Cover resolution is low
                cover_cancel_element = self.driver.find_element_by_xpath('//div[contains(text(), "Cancel")]')
                print('Cover resolution is low, cancel directly')
                # Error handling
                if cover_cancel_element != '':
                    print('cancel cover resolution is low')
                    cover_cancel_element.click()
                    # Publish now
                    cover_publish_element = WebDriverWait(self.driver, 30).until(
                        lambda x: x.find_element_by_xpath('//button[contains(text(), "Publish")]')
                    )
                    cover_publish_element.click()
            except Exception as e:
                print('An exception occurred due to low cover resolution: %s' % e)
                pass
            # Click on draft
            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('Reacquire draft list')
            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):
        """
        Xigua video release draft
        base_url: Xigua video website
        cookies_file_path: Xigua Video cookies file path
        """
        self.driver.get(base_url)
        # Load cookies
        XiGua.load_cookies(self, cookies_file_path)
        #Draft release video
        XiGua.videos_release(self)
        # Close browser
        XiGua.close(self)

    def xigua_batch_upload(self, base_url, cookies_file_path, videos_dir_path):
        """
        Xigua Video releases videos in batches
        base_url: Xigua video website
        cookies_file_path: Xigua Video cookies file path
        videos_dir_path: upload video storage 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):
        """
        Save website cookies
        base_url: website address
        cookies_file_path: website cookies file path
        """
        self.driver.get(base_url)
        # Save 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. Save cookie
    # xi_gua.xigua_save_cookies(base_url, 'xigua_cookies.txt')
    ## 2. Batch upload
    xi_gua.xigua_batch_upload(base_url, xigua_cookies, videos_dir_path)
    ## 3. Publish drafts in batches
    # xi_gua.xigua_videos_release(base_url, xigua_cookies)

Finally, I would like to thank everyone who read my article carefully. Reciprocity is always necessary. Although it is not a very valuable thing, if you can use it, you can take it directly:

This information should be the most comprehensive and complete preparation warehouse for [software testing] friends. This warehouse has also accompanied tens of thousands of test engineers through the most difficult journey. I hope it can also help you!

The knowledge points of the article match the official knowledge files, and you can further learn relevant knowledge. Python entry skill treeWeb crawlerSelenium386405 people are learning the system