Automating YouTube Music with Selenium in Python allows you to easily control and manipulate the playback of songs on the platform. This can be a great way to quickly and easily create a personalized listening experience without having to manually navigate through the website. Here, we will see how we can automate YouTube music with selenium in Python.
Prerequisites:
- Selenium: Automation of browsers.
- localStoragePy: Storing small strings permanently in JSON format, you can install from here, https://pypi.org/project/localStoragePy/
- Firefox: Since Google Chrome does not allow extensions to be used in headless mode [when the browser is running in the background], we must use a different browser such as Firefox in order to utilize extensions with Selenium.
- In order to automate Firefox using Selenium, we must install Geckodriver.exe, (https://github.com/mozilla/geckodriver/releases) which is the official browser automation engine for Selenium.
Stepwise Implementation
Step 1: Import the modules required.
Python3
from time import sleep from selenium import webdriver from selenium.webdriver.firefox.service import Service from localStoragePy import localStoragePy |
Step 2: Setting up local storage to save playlist URLs.
Python3
ls = localStoragePy( "<NAME OF DATABASE>" , "json" ) |
Step 3: To begin automating Firefox using Selenium, we need to initialize our webdriver. Also, we need to set the path for our Firefox browser and install the Geckodriver.exe in the path of this .py file. Here, we use the “Options” class to add various properties to our webdriver for optimized performance.
Python3
options = webdriver.FirefoxOptions() user_agent = ' - - user - agent = Mozilla / 5.0 (iPhone; \ CPU iPhone OS 10_3 like Mac OS X) \ AppleWebKit / 602.1 . 50 (KHTML, like Gecko) \ CriOS / 56.0 . 2924.75 Mobile / 14E5239e Safari / 602.1 ' options.add_argument(user_agent) options.binary_location = r 'C:\Program Files\Mozilla Firefox\firefox.exe' options.add_argument( "--headless" ) options.add_argument( "--log-level" ) options.add_argument( '--disable-application-cache' ) ser = Service( "geckodriver.exe" ) driver = webdriver.Firefox(service = ser, options = options) |
Step 4: In order to stream music without ads using our webdriver, we need to enable an ad blocker extension. To do this, we will need to obtain a .xpi file for the desired ad blocker extension. The .xpi file is a type of compressed file that contains the extension and its components. You can follow Step 1 at the linked webpage to learn how to obtain the .xpi file for your extension. Once you download the .xpi file, copy its path and set it as a variable, and initialize it in the webdriver
Python3
driver.install_addon(extension1, temporary = True ) |
Step 5: For our music player, we will be adding a function called Stream/Pause Music, Name of Track, and Add/Play/Remove Playlist and Stop. This function will allow the user to search for and play a specific song on YouTube using the webdriver.
To accomplish this, we will use the webdriver to search for the song using the provided URL. The webdriver will then click on the first video in the search results by locating its element using the “Inspect Element” feature and the XPath.
Finally, we will use the URL and the xpath to navigate to and access the desired video using the webdriver.”
Python3
def stream(MusicName): MusicName = MusicName driver.implicitly_wait( 3 ) video = driver.find_element( "xpath" , " / html / body / ytd - app / div[ 1 ] / ytd - page - manager / \ ytd - search / div[ 1 ] / ytd - two - column - search - results - renderer / \ div[ 2 ] / div / ytd - section - list - renderer / div[ 2 ] / \ ytd - item - section - renderer / div[ 3 ] / ytd - video - renderer[ 1 ] / \ div[ 1 ] / div / div[ 1 ] / div / h3 / a / yt - formatted - string") video.click() def pauseAndPlay(): pauseVideo = driver.find_element( "xpath" , " / html / body / ytd - app / div[ 1 ] / ytd - page - manager / \ ytd - watch - flexy / div[ 5 ] / div[ 1 ] / div / div[ 1 ] / div[ 2 ] / div / div / \ ytd - player / div / div / div[ 1 ] / video") driver.implicitly_wait( 1 ) pauseVideo.click() def track(): track = driver.find_element( "xpath" , " / html / body / ytd - app / div[ 1 ] / ytd - page - manager / \ ytd - watch - flexy / div[ 5 ] / div[ 1 ] / div / div[ 2 ] / ytd - watch - metadata / \ div / div[ 1 ] / h1 / yt - formatted - string") artist = driver.find_element( "xpath" , " / html / body / ytd - app / div[ 1 ] / ytd - page - manager\ / ytd - watch - flexy / div[ 5 ] / div[ 1 ] / div / div[ 2 ] / ytd - watch - metadata\ / div / div[ 2 ] / div[ 1 ] / ytd - video - owner - renderer / div[ 1 ] / \ ytd - channel - name / div / div / yt - formatted - string / a") print (f "{track.text} - {artist.text}" ) def streamPlaylist(playlistName): url = ls.getItem(playlistName) if url ! = None : driver.get(url) driver.implicitly_wait( 2.5 ) shuffle = driver.find_element( "xpath" , " / html / body / ytd - app / div[ 1 ] / ytd - page - manager / \ ytd - browse / ytd - playlist - header - renderer / div / div[ 2 ] / div[ 1 ] / \ div / div[ 2 ] / ytd - button - renderer[ 2 ] / yt - button - shape / \ a / yt - touch - feedback - shape / div / div[ 2 ]") shuffle.click() else : print ( "playlist not found......" ) print ( "re enter name properly" ) def addPlaylist(name, url): ls.setItem(name, url) sleep( 1 ) print ( "stored...." ) def removePlaylist(playlistName): ls.removeItem(playlistName) print ( "removed...." ) def stop(): driver.quit() exit( 1 ) |
Step 6: Finally, we add a driver code so that we can use the music player.
Python3
# we need to use st {songname} for our player to stream the song if __name__ = = "__main__" : print ( "Enter the name of song" ) while True : uinput = str ( input ()) # splitting the uinput in 2 strings and access the first string if uinput.split( " " , 1 )[ 0 ] = = "st" : songName = uinput.split( " " , 1 )[ 1 ] stream(songName) elif uinput = = "track" : track() elif uinput = = 'add' : url = str ( input ( "enter url of playlist" )) Name = str ( input ( "enter name of playlist:" )) addPlaylist(Name, url) elif uinput = = "pt" : pName = uinput.split( " " , 1 )[ 1 ] streamPlaylist(pName) elif uinput.split( " " , 1 )[ 0 ] = = "rem" : name = str ( input ( "Enter name to remove playlist" ) removePlaylist(name) elif uinput = = "stop" : stop() else : print ( "invalid command" ) |
Complete Code
Python3
from time import sleep from selenium import webdriver from selenium.webdriver.firefox.service import Service from localStoragePy import localStoragePy ls = localStoragePy( "<NAME OF DATABASE>" , "json" ) options = webdriver.FirefoxOptions() user_agent = '--user-agent=Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/602.1.50 (KHTML, like Gecko) CriOS/56.0.2924.75 Mobile/14E5239e Safari/602.1' options.add_argument(user_agent) options.binary_location = r 'C:\Program Files\Mozilla Firefox\firefox.exe' options.add_argument( "--headless" ) options.add_argument( "--log-level" ) options.add_argument( '--disable-application-cache' ) ser = Service( "geckodriver.exe" ) driver = webdriver.Firefox(service = ser, options = options) def stream(MusicName): MusicName = MusicName driver.implicitly_wait( 3 ) video = driver.find_element( "xpath" , "/html/body/ytd-app/div[1]/ytd-page-manager/ytd-search/div[1]/ytd-two-column-search-results-renderer/div[2]/div/ytd-section-list-renderer/div[2]/ytd-item-section-renderer/div[3]/ytd-video-renderer[1]/div[1]/div/div[1]/div/h3/a/yt-formatted-string" ) video.click() def pauseAndPlay(): pauseVideo = driver.find_element( "xpath" , "/html/body/ytd-app/div[1]/ytd-page-manager/ytd-watch-flexy/div[5]/div[1]/div/div[1]/div[2]/div/div/ytd-player/div/div/div[1]/video" ) driver.implicitly_wait( 1 ) pauseVideo.click() def track(): track = driver.find_element( "xpath" , "/html/body/ytd-app/div[1]/ytd-page-manager/ytd-watch-flexy/div[5]/div[1]/div/div[2]/ytd-watch-metadata/div/div[1]/h1/yt-formatted-string" ) artist = driver.find_element( "xpath" , "/html/body/ytd-app/div[1]/ytd-page-manager/ytd-watch-flexy/div[5]/div[1]/div/div[2]/ytd-watch-metadata/div/div[2]/div[1]/ytd-video-owner-renderer/div[1]/ytd-channel-name/div/div/yt-formatted-string/a" ) print (f "{track.text} - {artist.text}" ) def streamPlaylist(playlistName): url = ls.getItem(playlistName) if url ! = None : driver.get(url) driver.implicitly_wait( 2.5 ) shuffle = driver.find_element( "xpath" , "/html/body/ytd-app/div[1]/ytd-page-manager/ytd-browse/ytd-playlist-header-renderer/div/div[2]/div[1]/div/div[2]/ytd-button-renderer[2]/yt-button-shape/a/yt-touch-feedback-shape/div/div[2]" ) shuffle.click() else : print ( "playlist not found......" ) print ( "re enter name properly" ) def addPlaylist(name, url): ls.setItem(name, url) sleep( 1 ) print ( "stored...." ) def removePlaylist(playlistName): ls.removeItem(playlistName) print ( "removed...." ) def stop(): driver.quit() exit( 1 ) # we need to use Stream {songname} for our player to stream the song if __name__ = = "__main__" : print ( "Enter the name of song" ) while True : uinput = str ( input ()) # splitting the uinput in 2 strings and access the first string if uinput.split( " " , 1 )[ 0 ] = = "st" : songName = uinput.split( " " , 1 )[ 1 ] stream(songName) elif uinput = = "track" : track() elif uinput = = 'add' : url = str ( input ( "enter url of playlist" )) Name = str ( input ( "enter name of playlist:" )) addPlaylist(Name, url) elif uinput.split( " " , 1 )[ 0 ] = = "pt" : pName = uinput.split( " " , 1 )[ 1 ] streamPlaylist(pName) elif uinput.split( " " , 1 )[ 0 ] = = "rem" : name = uinput.split( " " , 1 )[ 1 ] removePlaylist(name) elif uinput = = "stop" : stop() else : print ( "invalid command" ) |
Output:
Drawbacks
- Internet Speed: When using Firefox and Selenium to control YouTube, It is important to keep in mind that poor internet speed may cause issues with playback and command execution. To prevent these issues, you can use exception handling and create a try/catch loop in your code. This will allow you to handle any errors that may occur due to slow internet speeds and ensure that your script continues to run smoothly.
- CPU Usage: Firefox is known to use a significant amount of CPU on its own, but when combined with Selenium, the CPU usage can become even more excessive. It is not uncommon for the combination of Firefox and Selenium to use up to 25% of a mid-range laptop’s CPU when active.
- Not using the stop() command: If you forget to use the stop() command and close the terminal, an instance of Firefox will remain open in the background. This can be a problem, especially on older laptops, as it can lead to unnecessary background tasks running.