Downloading videos serves a multitude of purposes, from ensuring offline access when you may have limited internet access to archiving important content for further analysis and processing. Ensure that before downloading a video, you respect the legal technicalities of the specific site and its boundaries.
Here are three ways to download a video from a URL with Python:
- Using requests module
- Using urllib module
- Using FFMpeg via subprocess
To demonstrate this tutorial, we will use free and open-source URLs that allow us to download videos in our local system. Those URLs are:
https://static.videezy.com/system/resources/previews/000/008/220/original/Triangles_01.mp4 https://www.shutterstock.com/shutterstock/videos/1111470671/preview/stock-footage-electric-light-bulb-bright-polygonal-connections-on-a-dark-blue-background-technology-concept.webm
Shutterstock is a famous website where you can find free licensed images and videos that you can use for educational purposes. My intent here is to teach you how to do it and not do it illegally. Having said that, let’s explore three ways.
Method 1: Using the “requests” module
The requests module provides a “requests.get()” method to download video files with streaming enabled. If any type of error occurs during the process, we will catch and print it. If the file is too large then download it in chunks and then save it locally.
Decision Tree Diagram
The above diagram denotes the process flow. It is a basic overview of how operations will be done.
Install the “requests” library using the command below:
pip install requests
Code example
import requests import os # Custom function that accepts url and local save_path def download_video(url, save_path): try: # Ensuring the directory exists os.makedirs(os.path.dirname(save_path), exist_ok=True) # Requesting the video file with streaming response = requests.get(url, stream=True) response.raise_for_status() # Check for HTTP errors # Getting the total file size from the response headers (optional) total_size = int(response.headers.get('content-length', 0)) # Download and save the video in chunks with open(save_path, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): if chunk: # Filter out keep-alive new chunks f.write(chunk) print(f"Video downloaded successfully and saved to {save_path}") # Catch and print the exceptions except requests.exceptions.HTTPError as e: print(f"HTTP error occurred: {e}") except requests.exceptions.RequestException as e: print(f"Request error occurred: {e}") except Exception as e: print(f"An error occurred: {e}") # Calling the custom function with video_url and save path video_url = 'https://static.videezy.com/system/resources/previews/000/008/220/original/Triangles_01.mp4' save_path = './videos/sample.mp4' download_video(video_url, save_path)
Output
Video downloaded successfully and saved to ./videos/sample.mp4
In my current project folder, there is a “videos” folder and I saved the video sample.mp4 inside this folder.
The requests library approach is easy to implement, has clear syntax, and fastest approach to downloading a video.
However, if the download is interrupted then it does not natively support to resume it. Moreover, if you are working with complex streaming protocols then it might not work either.
This approach is ideal when you just have a URL and it does not have authentication or require additional processing to fetch it.
The time complexity for the process is O(n), where n is the video file size. If the file is big, it will take a longer time.
The space complexity is O(1) as it writes a file in chunks without loading it entirely into a memory.
Method 2: Using the “urllib” module
When you are working with the “urllib” library, make sure that you are creating a secure connection using the ssl.create_default_context() function with the certifi library. Python certifi is a third-party package that provides Mozilla’s CA Bundle.
Open the URL with SSL and start reading video data. If you do not encounter any error then read the video in chunks and save it to the specified file locally. While downloading, display the progress and once the video is downloaded, print the success message.
Decision Tree Diagram
The above diagram describes visually what we will do programmatically. It will give you a step-by-step process.
Install the certifi library using the command below:
pip install certifi
Also, install ssl module:
pip install ssl
Code example
import urllib.request import os import ssl import certifi # Custom function to download a video def download_video(url, save_path): try: # Ensuring the directory exists os.makedirs(os.path.dirname(save_path), exist_ok=True) # Creating an SSL context using certifi's CA bundle context = ssl.create_default_context(cafile=certifi.where()) # Opening the URL with the SSL context with urllib.request.urlopen(url, context=context) as response: total_size = int(response.getheader('Content-Length', 0)) block_size = 8192 # 8 Kibibytes downloaded = 0 with open(save_path, 'wb') as out_file: while True: buffer = response.read(block_size) if not buffer: break out_file.write(buffer) downloaded += len(buffer) if total_size > 0: percent = downloaded / total_size * 100 print(f"\rDownloading: {percent:.2f}%", end='') else: print(f"\rDownloaded: {downloaded} bytes", end='') print(f"\nVideo downloaded successfully and saved to {save_path}") # Printing the error if occurs except urllib.error.URLError as e: print(f"URL Error: {e.reason}") except urllib.error.HTTPError as e: print(f"HTTP Error: {e.code} {e.reason}") except Exception as e: print(f"An unexpected error occurred: {e}") # Calling the custom function with input url and output directory video_url = 'https://www.shutterstock.com/shutterstock/videos/1111470671/preview/stock-footage-electric-light-bulb-bright-polygonal-connections-on-a-dark-blue-background-technology-concept.webm' save_path = './videos/urllib_video.mp4' download_video(video_url, save_path)
Output
Downloading: 100.00% Video downloaded successfully and saved to ./videos/urllib_video.mp4
It provides limited flexibility compared to the “requests” module approach and is harder to handle the chunked downloads. It is suitable for simpler downloads where authentication is not required and streaming is not needed.
The time complexity is O(n) where n depends on the size of the video.
The space complexity is O(1).
Method 3: Using ffmpeg via subprocess
It is a very simple solution where you just need to create a command FFMpeg command and run it using the subprocess module. When the command is running, it will start the process of downloading a file and if it encounters an error, it will print it on the console.
Decision Tree Diagram
The above figure is very simple where we created a command and ran it to fetch the video.
This approach requires the “ffmpeg” library installed on your machine. I am using MacOS, so I can download it if I have not by the command below:
brew install ffmpeg
If you are using Windows or Linux then go to its website and download it.
Code example
import subprocess import os # Creating a custom function def download_video_ffmpeg(url, save_path): try: # Ensuring the directory exists os.makedirs(os.path.dirname(save_path), exist_ok=True) # FFmpeg command to download video command = [ 'ffmpeg', '-i', url, '-c', 'copy', save_path ] # Running the FFmpeg command subprocess.run(command, check=True) print(f"Video downloaded successfully and saved to {save_path}") # Catching and print the exceptions except FileNotFoundError as e: print( f"Error: {e}. Ensure FFmpeg is installed and available in your PATH.") except subprocess.CalledProcessError as e: print(f"Error downloading video: {e}") except Exception as e: print(f"An unexpected error occurred: {e}") # Calling the custom function video_url = 'https://static.videezy.com/system/resources/previews/000/008/220/original/Triangles_01.mp4' save_path = './videos/ffmpeg_video.mp4' download_video_ffmpeg(video_url, save_path)
Output
Here is the video stored locally:
The ffmpeg via subprocess approach is a powerful method that can handle various streaming protocols, formats, and encoding. It can process large multimedia files.
However, you need to install ffmpeg and you must know how to deal with command-line tools. It can be the slowest approach among the three.
The ffmpeg method is ideal when you are processing and downloading videos from streaming. If you want to stream and perform manipulative tasks then I highly recommend you to use this approach.
The time complexity is O(n), where n is the size of the video.
The space complexity is O(n) because here we are streaming it in real-time.
Time measurement to execute each method
I ran an experiment to execute all three approaches and record their time and not so surprisingly, the fastest approach is using the “requests” module, and the slowest approach is “ffmpeg via subprocess”.
Here is the bar chart supporting my findings:
You can see from the above bar chart that the “requests” took 0.16s and FFmpeg took 0.47s. And here, I took the same URL for all of the methods to get accurate results.