【问题标题】:Python (3.5) - urllib.request.urlopen - Progress Bar Available?Python (3.5) - urllib.request.urlopen - 进度条可用吗?
【发布时间】:2017-04-27 15:47:43
【问题描述】:

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

如果文件超过 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)

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

【问题讨论】:

  • 这实际上与urllib 无关,是吗?而是问题在于copyfileobj() 不提供进度回调。那么dup?
  • 我建议切换到python requests
  • 为了构建一个进度条,您需要知道您将要下载的数据的总大小及其下载部分的当前大小。第一个可以从Content-Length 标头中检索。您可以通过reading 指定大小的数据块并计算块长度的总和来计算第二个。 requests 库可让您 read 来自连接的数据块。

标签: python urllib python-3.5


【解决方案1】:

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

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()

【讨论】:

  • 您好,感谢您的回复。我在一个单独的文件中尝试了这个,我得到的错误是第 24 行 TypeError: 'float' object is not iterable
  • 我应该做地板分割。我已将示例更改为blocksize = max(4096, length//100)。 (我只测试了一个小文件!)
  • 太棒了,该代码正在运行。你知道如何将它应用到我的下载中吗?我会调整它并将其放在with urllib.request.urlopen 下吗?
  • 是的,它取代了 shutil 的东西。
  • 太好了,这似乎工作了!作为最后一个问题,是否可以更新同一行而不是在新行上打印新百分比?如果没有,没关系,非常感谢您的帮助和时间。
【解决方案2】:

@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()))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-10-19
    • 1970-01-01
    • 2022-01-16
    • 1970-01-01
    • 2016-03-12
    • 2011-03-10
    相关资源
    最近更新 更多