Python Progress Bar and Downloads

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.

Sample Image

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



Leave a reply



Submit