Python 3 Selenium YouTube API Bot to Upload 10 Videos per Day Automatically to Increase Traffic on Command Line – Coding Deekshi

Today we are going to discuss this important topic via this article Python 3 Selenium YouTube API Bot to Upload 10 Videos per Day Automatically to Increase Traffic on Command Line. We hope you like this article.

Python 3 Selenium YouTube API Bot to Upload 10 Videos per Day Automatically to Increase Traffic on Command LinePython 3 Selenium YouTube API Bot to Upload 10 Videos per Day Automatically to Increase Traffic on Command Line

Python 3 Selenium YouTube API Bot to Upload 10 Videos per Day Automatically to Increase Traffic on Command Line

pip3 install --upgrade youtube-uploader-selenium
git clone https://github.com/linouk23/youtube_uploader_selenium
<span class="pl-c1">cd</span> youtube-uploader-selenium
<span class="pl-k">from</span> <span class="pl-s1">youtube_uploader_selenium</span> <span class="pl-k">import</span> <span class="pl-v">YouTubeUploader</span>
 
<span class="pl-s1">video_path</span> <span class="pl-c1">=</span> <span class="pl-s">'123/rockets.flv'</span>
<span class="pl-s1">metadata_path</span> <span class="pl-c1">=</span> <span class="pl-s">'123/rockets_metadata.json'</span>
 
<span class="pl-s1">uploader</span> <span class="pl-c1">=</span> <span class="pl-v">YouTubeUploader</span>(<span class="pl-s1">video_path</span>, <span class="pl-s1">metadata_path</span>, <span class="pl-s1">thumbnail_path</span>)
<span class="pl-s1">was_video_uploaded</span>, <span class="pl-s1">video_id</span> <span class="pl-c1">=</span> <span class="pl-s1">uploader</span>.<span class="pl-en">upload</span>()
<span class="pl-k">assert</span> <span class="pl-s1">was_video_uploaded</span>
python3 upload.py --video rockets.flv
python3 upload.py --video rockets.flv --meta metadata.json
{
  <span class="pl-ent">"title"</span>: <span class="pl-s"><span class="pl-pds">"</span>Best Of James Harden | 2019-20 NBA Season<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"description"</span>: <span class="pl-s"><span class="pl-pds">"</span>Check out the best of James Harden's 2019-20 season so far!<span class="pl-pds">"</span></span>,
  <span class="pl-ent">"tags"</span>: [<span class="pl-s"><span class="pl-pds">"</span>James<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>Harden<span class="pl-pds">"</span></span>, <span class="pl-s"><span class="pl-pds">"</span>NBA<span class="pl-pds">"</span></span>]
}
import argparse
from youtube_uploader_selenium import YouTubeUploader
from typing import Optional
 
 
def main(video_path: str, metadata_path: Optional[str] = None, thumbnail_path: Optional[str] = None):
    uploader = YouTubeUploader(video_path, metadata_path, thumbnail_path)
    was_video_uploaded, video_id = uploader.upload()
    assert was_video_uploaded
 
 
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument("--video",
                        help='Path to the video file',
                        required=True)
    parser.add_argument("-t",
                        "--thumbnail",
                        help='Path to the thumbnail image',)
    parser.add_argument("--meta", help='Path to the JSON file with metadata')
    args = parser.parse_args()
    main(args.video, args.meta, args.thumbnail)
class Constant:
    """A class for storing constants for YoutubeUploader class"""



    YOUTUBE_URL = 'https://www.youtube.com'
    YOUTUBE_STUDIO_URL = 'https://studio.youtube.com'
    YOUTUBE_UPLOAD_URL = 'https://www.youtube.com/upload'
    USER_WAITING_TIME = 1
    VIDEO_TITLE = 'title'
    VIDEO_DESCRIPTION = 'description'
    VIDEO_TAGS = 'tags'
    DESCRIPTION_CONTAINER = '/html/body/ytcp-uploads-dialog/tp-yt-paper-dialog/div/ytcp-animatable[1]/' \
                            'ytcp-uploads-details/div/ytcp-uploads-basics/ytcp-mention-textbox[2]'
    TEXTBOX = 'textbox'
    TEXT_INPUT = 'text-input'
    RADIO_LABEL = 'radioLabel'
    STATUS_CONTAINER = '/html/body/ytcp-uploads-dialog/tp-yt-paper-dialog/div/ytcp-animatable[2]/' \
                       'div/div[1]/ytcp-video-upload-progress/span'
    NOT_MADE_FOR_KIDS_LABEL = 'VIDEO_MADE_FOR_KIDS_NOT_MFK'
 
    # Thanks to romka777
    MORE_BUTTON = '/html/body/ytcp-uploads-dialog/tp-yt-paper-dialog/div/ytcp-animatable[1]/ytcp-video-metadata-editor/div/div/ytcp-button/div'
    TAGS_INPUT_CONTAINER = '/html/body/ytcp-uploads-dialog/tp-yt-paper-dialog/div/ytcp-animatable[1]/ytcp-video-metadata-editor/div/ytcp-video-metadata-editor-advanced/div[3]/ytcp-form-input-container/div[1]/div[2]/ytcp-free-text-chip-bar/ytcp-chip-bar/div'
 
    TAGS_INPUT = 'text-input'
    NEXT_BUTTON = 'next-button'
    PUBLIC_BUTTON = 'PUBLIC'
    VIDEO_URL_CONTAINER = "//span[@class="video-url-fadeable style-scope ytcp-video-info"]"
    VIDEO_URL_ELEMENT = "//a[@class="style-scope ytcp-video-info"]"
    HREF = "https://codingdiksha.com/python-selenium-youtube-api-bot-to-upload-10-videos-per-day-automatically-to-increase-traffic-on-command-line/href"
    UPLOADED = 'Uploading'
    ERROR_CONTAINER = '//*[@id="error-message"]'
    VIDEO_NOT_FOUND_ERROR = 'Could not find video_id'
    DONE_BUTTON = 'done-button'
    INPUT_FILE_VIDEO = "//input[@type="file"]"
    INPUT_FILE_THUMBNAIL = "//input[@id='file-loader']"
"""This module implements uploading videos on YouTube via Selenium using metadata JSON file



to extract its title, description etc."""
 
from typing import DefaultDict, Optional
from selenium_firefox.firefox import Firefox, By, Keys
from collections import defaultdict
import json
import time
from .Constant import *
from pathlib import Path
import logging
import platform
 
logging.basicConfig()
 
 
def load_metadata(metadata_json_path: Optional[str] = None) -> DefaultDict[str, str]:
if metadata_json_path is None:
return defaultdict(str)
with open(metadata_json_path, encoding='utf-8') as metadata_json_file:
return defaultdict(str, json.load(metadata_json_file))
 
 
class YouTubeUploader:
"""A class for uploading videos on YouTube via Selenium using metadata JSON file
to extract its title, description etc"""
 
def __init__(self, video_path: str, metadata_json_path: Optional[str] = None, thumbnail_path: Optional[str] = None) -> None:
self.video_path = video_path
self.thumbnail_path = thumbnail_path
self.metadata_dict = load_metadata(metadata_json_path)
current_working_dir = str(Path.cwd())
self.browser = Firefox(current_working_dir, current_working_dir)
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.DEBUG)
self.__validate_inputs()

self.is_mac = False



if not any(os_name in platform.platform() for os_name in ["Windows", "Linux"]):
self.is_mac = True
 
def __validate_inputs(self):
if not self.metadata_dict[Constant.VIDEO_TITLE]:
self.logger.warning(
"The video title was not found in a metadata file")
self.metadata_dict[Constant.VIDEO_TITLE] = Path(
self.video_path).stem
self.logger.warning("The video title was set to {}".format(
Path(self.video_path).stem))
if not self.metadata_dict[Constant.VIDEO_DESCRIPTION]:
self.logger.warning(
"The video description was not found in a metadata file")
 
def upload(self):
try:
self.__login()
return self.__upload()
except Exception as e:
print(e)
self.__quit()
raise
 
def __login(self):
self.browser.get(Constant.YOUTUBE_URL)
time.sleep(Constant.USER_WAITING_TIME)
 
if self.browser.has_cookies_for_current_website():
self.browser.load_cookies()
time.sleep(Constant.USER_WAITING_TIME)
self.browser.refresh()
else:
self.logger.info('Please sign in and then press enter')
input()
self.browser.get(Constant.YOUTUBE_URL)
time.sleep(Constant.USER_WAITING_TIME)
self.browser.save_cookies()
 
def __write_in_field(self, field, string, select_all=False):



field.click()
 
time.sleep(Constant.USER_WAITING_TIME)
if select_all:
if self.is_mac:
field.send_keys(Keys.COMMAND + 'a')
else:
field.send_keys(Keys.CONTROL + 'a')
time.sleep(Constant.USER_WAITING_TIME)
field.send_keys(string)
 
def __upload(self) -> (bool, Optional[str]):
self.browser.get(Constant.YOUTUBE_URL)
time.sleep(Constant.USER_WAITING_TIME)
self.browser.get(Constant.YOUTUBE_UPLOAD_URL)
time.sleep(Constant.USER_WAITING_TIME)
absolute_video_path = str(Path.cwd() / self.video_path)
self.browser.find(By.XPATH, Constant.INPUT_FILE_VIDEO).send_keys(
absolute_video_path)
self.logger.debug('Attached video {}'.format(self.video_path))
 
if self.thumbnail_path is not None:
absolute_thumbnail_path = str(Path.cwd() / self.thumbnail_path)
self.browser.find(By.XPATH, Constant.INPUT_FILE_THUMBNAIL).send_keys(
absolute_thumbnail_path)
change_display = "document.getElementById('file-loader').style="display: block! important""
self.browser.driver.execute_script(change_display)
self.logger.debug(
'Attached thumbnail {}'.format(self.thumbnail_path))
 
title_field = self.browser.find(By.ID, Constant.TEXTBOX, timeout=15)
self.__write_in_field(
title_field, self.metadata_dict[Constant.VIDEO_TITLE], select_all=True)
self.logger.debug('The video title was set to \"{}\"'.format(
self.metadata_dict[Constant.VIDEO_TITLE]))
 
video_description = self.metadata_dict[Constant.VIDEO_DESCRIPTION]
video_description = video_description.replace("\n", Keys.ENTER);
if video_description:
description_field = self.browser.find_all(By.ID, Constant.TEXTBOX)[1]
self.__write_in_field(description_field, video_description, select_all=True)
self.logger.debug('Description filled.')
 
kids_section = self.browser.find(
By.NAME, Constant.NOT_MADE_FOR_KIDS_LABEL)
self.browser.find(By.ID, Constant.RADIO_LABEL, kids_section).click()
self.logger.debug('Selected \"{}\"'.format(
Constant.NOT_MADE_FOR_KIDS_LABEL))
 
# Advanced options
self.browser.find(By.XPATH, Constant.MORE_BUTTON).click()
self.logger.debug('Clicked MORE OPTIONS')
 
tags_container = self.browser.find(By.XPATH,
   Constant.TAGS_INPUT_CONTAINER)
tags_field = self.browser.find(
By.ID, Constant.TAGS_INPUT, element=tags_container)
self.__write_in_field(tags_field, ','.join(
self.metadata_dict[Constant.VIDEO_TAGS]))
self.logger.debug(
'The tags were set to \"{}\"'.format(self.metadata_dict[Constant.VIDEO_TAGS]))
 
 
self.browser.find(By.ID, Constant.NEXT_BUTTON).click()
self.logger.debug('Clicked {} one'.format(Constant.NEXT_BUTTON))
 
# Thanks to romka777
self.browser.find(By.ID, Constant.NEXT_BUTTON).click()
self.logger.debug('Clicked {} two'.format(Constant.NEXT_BUTTON))
 
self.browser.find(By.ID, Constant.NEXT_BUTTON).click()



self.logger.debug('Clicked {} three'.format(Constant.NEXT_BUTTON))
public_main_button = self.browser.find(By.NAME, Constant.PUBLIC_BUTTON)
self.browser.find(By.ID, Constant.RADIO_LABEL,
  public_main_button).click()
self.logger.debug('Made the video {}'.format(Constant.PUBLIC_BUTTON))
 
video_id = self.__get_video_id()
 
status_container = self.browser.find(By.XPATH,
Constant.STATUS_CONTAINER)
while True:
in_process = status_container.text.find(Constant.UPLOADED) != -1
if in_process:
time.sleep(Constant.USER_WAITING_TIME)
else:
break
 
done_button = self.browser.find(By.ID, Constant.DONE_BUTTON)
 
# Catch such error as
# "File is a duplicate of a video you have already uploaded"
if done_button.get_attribute('aria-disabled') == 'true':
error_message = self.browser.find(By.XPATH,
  Constant.ERROR_CONTAINER).text
self.logger.error(error_message)
return False, None
 
done_button.click()
self.logger.debug(
"Published the video with video_id = {}".format(video_id))
time.sleep(Constant.USER_WAITING_TIME)
self.browser.get(Constant.YOUTUBE_URL)
self.__quit()
return True, video_id
 
def __get_video_id(self) -> Optional[str]:
video_id = None
try:
video_url_container = self.browser.find(
By.XPATH, Constant.VIDEO_URL_CONTAINER)
video_url_element = self.browser.find(By.XPATH, Constant.VIDEO_URL_ELEMENT,
  element=video_url_container)
video_id = video_url_element.get_attribute(
Constant.HREF).split('/')[-1]
except:
self.logger.warning(Constant.VIDEO_NOT_FOUND_ERROR)
pass
return video_id
 
def __quit(self):
self.browser.driver.quit()

Final Words

Python 3 Selenium YouTube API Bot to Upload 10 Videos per Day Automatically to Increase Traffic on Command Line We learned about this very clearly through this article. And if you liked this article please share it with your friend.