How do I make progress bar while downloading file in python
from tqdm import *
import requests
url = "https://as2.cdn.asset.aparat.com/aparat-video/520055aa72618571e4ce34b434e328b615570838-144p__58945.mp4"
name = "video"
with requests.get(url, stream=True) as r:
r.raise_for_status()
with open(name, 'wb') as f:
pbar = tqdm(total=int(r.headers['Content-Length']))
for chunk in r.iter_content(chunk_size=8192):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
pbar.update(len(chunk))
Progress Bar while download file over http with Requests
I suggest you try tqdm
, it's very easy to use.
Example code for downloading with requests
library:
from tqdm import tqdm
import requests
url = "http://www.ovh.net/files/10Mb.dat" #big file test
# Streaming, so we can iterate over the response.
response = requests.get(url, stream=True)
total_size_in_bytes= int(response.headers.get('content-length', 0))
block_size = 1024 #1 Kibibyte
progress_bar = tqdm(total=total_size_in_bytes, unit='iB', unit_scale=True)
with open('test.dat', 'wb') as file:
for data in response.iter_content(block_size):
progress_bar.update(len(data))
file.write(data)
progress_bar.close()
if total_size_in_bytes != 0 and progress_bar.n != total_size_in_bytes:
print("ERROR, something went wrong")
How to add pytube downloading info to tqdm Progress Bar?
To access the progress of the download, you can use the on_progress_callback
argument when creating a YouTube
instance.
The pytube quickstart says the following:
The on_progress_callback
function will run whenever a chunk is downloaded from a video, and is called with three arguments: the stream, the data chunk, and the bytes remaining in the video. This could be used, for example, to display a progress bar.
from pytube import Stream
from pytube import YouTube
from tqdm import tqdm
def progress_callback(stream: Stream, data_chunk: bytes, bytes_remaining: int) -> None:
pbar.update(len(data_chunk))
url = "http://youtube.com/watch?v=2lAe1cqCOXo"
yt = YouTube(url, on_progress_callback=progress_callback)
stream = yt.streams.get_highest_resolution()
print(f"Downloading video to '{stream.default_filename}'")
pbar = tqdm(total=stream.filesize, unit="bytes")
path = stream.download()
pbar.close()
print(f"Saved video to {path}")
Sample output:Downloading video to 'YouTube Rewind 2019 For the Record YouTubeRewind.mp4'
100%|██████████████████████████████| 87993287/87993287 [00:17<00:00, 4976219.51bytes/s]
Saved video to /tmp/testing/YouTube Rewind 2019 For the Record YouTubeRewind.mp4
Pytube has a built-in progress bar, but it does not use
tqdm
. Please see https://stackoverflow.com/a/60678355/5666087 for more information. Trouble with progressbar(tkinter) in a download file
I created example which uses Label
to display how many bytes remained to download.
If you get file length then you could calculate it as percentage.
YouTube()
can use on_progress_callback
and on_complete_callback
to execute functions during downloading and they can be used to display progress.These functions runs in new threads and they can't update widgets directly (it generate error) so I use Queue()
to send values from these functions to main thread. And main thread uses root.after()
to execute update_status()
every 100ms. And this function gets information from queue and update labels.
Every thread gets number
to later send it back and update_status()
which label to update
And similar way it could work with widgets Progressbar.
For test I added few links directly in code - so I did't have to put them manually in every run.
Because I use for
-loops and list
so I reduced code but still have 5 Entries, and can download 5 files at the same time. If I would use range(10)
then I could download 10 files.
Originally I created all_threads
to keep all threads and use is_alive()
to check finished threads but now I don't use this list.
I tried to keep only elements which are really important in example - so I removed fonts, colors, images.
from pytube import YouTube
import tkinter as tk # PEP8: `import *` is not preferred
from threading import Thread
from queue import Queue
# --- functions ---
def update_status():
# check if there are new messages in queue and update correct label
while not queue.empty():
number, text = queue.get()
print('[update_status]:', number, text)
all_labels[number]['text'] = text
root.after(100, update_status) # run again after 100ms
def on_progress(number, queue, stream, chunk, bytes_remaining):
print('[on_progress] bytes_remaining:', bytes_remaining)
queue.put( (number, bytes_remaining) )
def on_complete(number, queue, stream, file_path):
print('[on_complete] file_path:', file_path)
queue.put( (number, file_path) )
def download(url, number, queue):
print('[download] started:', url)
queue.put( (number, 'started') )
yt = YouTube(url,
on_progress_callback=lambda *args:on_progress(number, queue, *args),
on_complete_callback=lambda *args:on_complete(number, queue, *args),
)
video = yt.streams.get_highest_resolution()
video.download()
all_threads[number] = None # inform that finished
print('[download] finished:', url)
#queue.put( (number, 'finished') )
def start_threads():
for number, (t, entry) in enumerate(zip(all_threads, all_entries)):
url = entry.get().strip()
if url:
print('[start_threads]:', number, 'starting')
t = Thread(target=download, args=(url, number, queue))
t.start()
else:
print('[start_threads]:', number, 'empty')
t = None
all_threads[number] = t
# --- main ---
all_threads = [None] * 5 # to have all values at start
all_entries = []
all_labels = []
root = tk.Tk()
queue = Queue()
for n in range(5):
entry = tk.Entry(root, width=50)
entry.grid(column=0, row=n)
all_entries.append(entry)
label = tk.Label(root, width=15, text='-')
label.grid(column=1, row=n)
all_labels.append(label)
button = tk.Button(root, text='Start', command=start_threads)
button.grid(column=0, row=n+1, columnspan=2)
# for test I put some links so I don't have to do it manually
all_entries[0].insert('end', 'https://www.youtube.com/watch?v=aqz-KE-bpKQ')
all_entries[1].insert('end', 'https://www.youtube.com/watch?v=bNfYUsDSrOs')
all_entries[2].insert('end', 'https://www.youtube.com/watch?v=W7LWny6c4wI')
all_entries[3].insert('end', 'https://www.youtube.com/watch?v=A8LRxIANzQs')
update_status()
root.mainloop()
Python Progress Bar
There are specific libraries (like this one here) but maybe something very simple would do:
import time
import sys
toolbar_width = 40
# setup toolbar
sys.stdout.write("[%s]" % (" " * toolbar_width))
sys.stdout.flush()
sys.stdout.write("\b" * (toolbar_width+1)) # return to start of line, after '['
for i in range(toolbar_width):
time.sleep(0.1) # do real work here
# update the bar
sys.stdout.write("-")
sys.stdout.flush()
sys.stdout.write("]\n") # this ends the progress bar
Note: progressbar2 is a fork of progressbar which hasn't been maintained in years.
Related Topics
Generate Rfc 3339 Timestamp in Python
Rotating a Two-Dimensional Array in Python
How to Calculate the Inverse of the Normal Cumulative Distribution Function in Python
How to Ignore One Single Specific Line with Pylint
Why Does Python Use 'Magic Methods'
How to Save Final Model Using Keras
Preventing Python Code from Importing Certain Modules
Plotting Multiple Lines, in Different Colors, with Pandas Dataframe
What Is the Relationship Between Google's App Engine Sdk and Cloud Sdk
Does Python Evaluate If's Conditions Lazily
Continuing in Python's Unittest When an Assertion Fails
How to Find the Maximum Value in a List of Tuples
How to Suppress or Capture the Output of Subprocess.Run()
How Do Threads Work in Python, and What Are Common Python-Threading Specific Pitfalls
Find All Upper, Lower and Mixed Case Combinations of a String