The easiest way to download YouTube videos using Python | by Eryk Lewinson | Towards Data Science

In one of my first articles on Medium, I showed how to train a Convolutional Neural Network to classify images coming from old GameBoy games — Mario and Wario. After over a year, I wanted to revisit one aspect of the process — downloading videos (and potentially audio) from YouTube videos and extracting frames as images. We can use such images for various machine learning projects.
In my previous article, I used a library called pytube to download the videos. However, after some changes introduced by YouTube, it is not really usable anymore — any attempt to download videos results in KeyError: ‘url_encoded_fmt_stream_map’. Also, the library is not actively maintained anymore.
That is why in this article I suggest using pytube3, which is a fork of the original pytube library and has the error fixed (it only works with Python 3). All the functionalities of the original library are preserved and we actually still use import pytube to import the library (even though we install it using pip install pytube3).
Below I present the list of all the imports required for this article:
from pytube import YouTube# miscimport osimport shutilimport mathimport datetime# plotsimport matplotlib.pyplot as plt%matplotlib inline# image operationimport cv2
In this part, I present how to download a YouTube video using Python. I will use a classic video game from GameBoy — Mega Man: Dr. Wily’s Revenge. The first step is to create an instance of the YouTube class using the link to the video we want to download.
video = YouTube('https://www.youtube.com/watch?v=NqC_1GuY3dw')
Using this object, we can download the video/audio, and inspect some of the properties of the video itself. Some of the interesting methods we can use are:
length — length of the video in seconds
rating — the rating of the video
views — the number of views
The next step is to inspect the available streams using the streams method. We can chain it with the all method to see all the available streams.
video.streams.all()
Running that line of code returns the following list of media formats:
For a more in-depth description of the options regarding the media formats and working with streams, I refer to pytube’s documentation available here.
Let’s narrow down all the available streams to mp4 files using the filter method:
video.streams.filter(file_extension = "mp4").all()
Running the code results in the following selection:
In this case, we will use the first available option, the one in 360p (resolution). To download the video, we first indicate which one we want to download by using the itag and then download the file using the download method. The full code for downloading the video is as follows:
video.streams.get_by_itag(18).download()
In the download method, we can also specify the destination path for the video. The default value is the current directory.
I created a special class called FrameExtractor to — as the name pretty much reveals it — extract individual frames from the video and save them as images. The class is defined as follows:
While instantiating the object of the FrameExtractor class, we need to provide the path to the video we want to work with. In the __init__ method, we also extract some characteristics of the video such as the total number of frames and the frames per second (FPS). In general, the class provides functionality to extract every x-th frame from the video, as the difference between any two neighboring frames will be minimal. We provide a few convenience methods as well. All the methods are described below:
get_video_duration — prints the duration of the video
get_n_images — prints the number of images that will be extracted given we extract every x-th frame (indicated by every_x_frame)
extract_frames — this is the main method of the class, which is used to extract the images. The bare minimum is providing the value for every_x_frame and the name of the image (the numbers indicating the sequence will be added automatically at the end of the name). By default, the images will be saved in the current directory. We can also provide a path to the desired directory (dest_path), and if it does not exist, it will be created for us. We can also specify the format of the image file, the default is JPG.
Now it is time to actually use the class. We start by instantiating the object of the FrameExtractor class:
fe = FrameExtractor('Game Boy Longplay [009] Mega Man Dr Wilys Revenge.mp4')
Next, we investigate the length of the video:
fe.get_video_duration()# Duration: 0:39:48.333333
As an example, let’s assume we want to extract every 1000th frame. To calculate the number of images extracted using this setting, we run:
fe.get_n_images(every_x_frame=1000)# Extracting every 1000 (nd/rd/th) frame would result in 71 images.
As the last step, we extract the images:
fe.extract_frames(every_x_frame=1000,                   img_name='megaman',                   dest_path='megaman_images')# Created the following directory: megaman_images
The indicated directory did not exist prior to using the extract_frames method, so it was automatically created and we saw a printed statement confirming this.
Finally, we define a short function for viewing the downloaded images:
def show_image(path):    image = cv2.imread(path)    plt.imshow(image)    plt.show()show_image('megaman_images/megaman_61.jpg')
Running the code results in displaying the following image:
In this article, I described how to download videos from YouTube using the pytube3 library and coded a custom class used for extracting frames as images from the downloaded videos. A potential modification to the class is to account for skipping the first n seconds of the video, as the beginning often contains title screens, company logos, etc. The same could be done about the end of the video. However, for the time being, we can also account for that by manually deleting the images that are of no use to us.
You can find the code used for this article on my GitHub. As always, any constructive feedback is welcome. You can reach out to me on Twitter or in the comments.
Liked the article? Become a Medium member to continue learning by reading without limits. If you use this link to become a member, you will support me at no extra cost to you. Thanks in advance and see you around!
I recently published a book on using Python for solving practical tasks in the financial domain. If you are interested, I posted an article introducing the contents of the book. You can get the book on Amazon or Packt’s website.