Python (3.5) - urllib.request.urlopen - 进度条可用吗?

Python (3.5) - urllib.request.urlopen - Progress Bar Available?

我正试图在万维网上搜索这个答案,但我觉得答案可能是否定的。我正在使用 Python 3.5 和一个名为 urllib.request 的库以及一个名为 urllib.request.urlopen(url) 的方法来打开 link 并下载文件。

由于文件超过 200MB,最好对此进行某种进度衡量。我正在查看 API here,但没有看到任何带钩子的参数。

这是我的代码:

downloadURL = results[3] #got this from code earlier up
rel_path = account + '/' + eventID + '_' + title + '.mp4'

filename_abs_path = os.path.join(script_dir, rel_path)
print('>>> Downloading >>> ' + title)

# Download .mp4 from a url and save it locally under `file_name`:
with urllib.request.urlopen(downloadURL) as response, open(filename_abs_path, 'wb') as out_file:
    shutil.copyfileobj(response, out_file)

如果有人认为我可能有一个进度条或者唯一的方法是使用不同的库,他们可以提供见解吗?我希望让代码非常简短,我只需要一些正在下载的文件的指示。感谢您提供的任何帮助!

如果响应包含 content-length,您可以按块读取传入数据并计算完成百分比。不幸的是,"chunk" 响应的 Web 服务器并不总是提供内容长度,因此它并不总是有效。这是一个测试的例子。

import urllib.request
import sys
import io

try:
    url = sys.argv[1]
except IndexError:
    print("usage: test.py url")
    exit(2)

resp = urllib.request.urlopen(url)
length = resp.getheader('content-length')
if length:
    length = int(length)
    blocksize = max(4096, length//100)
else:
    blocksize = 1000000 # just made something up

print(length, blocksize)

buf = io.BytesIO()
size = 0
while True:
    buf1 = resp.read(blocksize)
    if not buf1:
        break
    buf.write(buf1)
    size += len(buf1)
    if length:
        print('{:.2f}\r done'.format(size/length), end='')
print()

@tdelaney 的回答很好,但是在 Python 3.8 中你必须使用 getvalue() 方法而不是 read():

    import io, urllib.request

    with urllib.request.urlopen(Url) as Response:
        Length = Response.getheader('content-length')
        BlockSize = 1000000  # default value

        if Length:
            Length = int(Length)
            BlockSize = max(4096, Length // 20)

        print("UrlLib len, blocksize: ", Length, BlockSize)

        BufferAll = io.BytesIO()
        Size = 0
        while True:
            BufferNow = Response.read(BlockSize)
            if not BufferNow:
                break
            BufferAll.write(BufferNow)
            Size += len(BufferNow)
            if Length:
                Percent = int((Size / Length)*100)
                print(f"download: {Percent}% {Url}")

        print("Buffer All len:", len(BufferAll.getvalue()))