【问题标题】:Download several parts of one file concurrently with Python?使用 Python 同时下载一个文件的多个部分?
【发布时间】:2023-03-19 06:31:01
【问题描述】:

我知道如何使用urllib 下载文件。但是,如果服务器允许,同时下载同一文件的多个部分然后合并它们会更快。

你如何在 Python 中做到这一点?如果您不能使用标准库轻松做到这一点,那么有什么库可以让您做到这一点?

【问题讨论】:

  • 通常,并行下载文件的多个部分不会快,因为您仍然受限于网络连接的瓶颈。只有当服务器每个连接只允许有限的带宽时,你才会得到改善。
  • 如果您以某种方式认为这将达到您使用 torrent 获得的下载速度,您会失望地发现这在单个客户端、单个服务器的情况下对您没有帮助. 更快如果您从多个来源下载并且每个来源的上传带宽都小于您的总下载带宽。没有比从单个服务器(可用)上传带宽大于或等于您的下载带宽直接下载更快的下载速度。
  • @Sven:那是错误的。在现实世界中,在与大多数服务器的大多数连接上,使用多个流下载通常要快得多。这很不幸,原因可能很难追查,但它就在那里,很多人别无选择,只能处理它。
  • +1 给格伦。理论上它不应该更快,实际上它几乎总是如此。
  • @Sven:远没有那么简单;您的网络不是每个网络。

标签: python download


【解决方案1】:

虽然我同意 Gregory 关于使用现有库的建议,但值得注意的是,您可以通过使用 Range HTTP 标头来做到这一点。如果服务器接受字节范围请求,您可以启动多个线程并行下载文件的多个部分。例如,这个 sn-p 只会下载指定文件的 0..65535 字节:

import urllib2
url = 'http://example.com/test.zip'
req = urllib2.Request(url, headers={'Range':'bytes=0-65535'})
data = urllib2.urlopen(req).read()

您可以通过发送 HEAD 请求来确定远程资源大小并查看服务器是否支持范围请求:

import urllib2

class HeadRequest(urllib2.Request):
    def get_method(self):
        return "HEAD"

url = 'http://sstatic.net/stackoverflow/img/sprites.png'
req = HeadRequest(url)
response = urllib2.urlopen(req)
response.close()
print respose.headers

以上打印:

Cache-Control: max-age=604800
Content-Length: 16542
Content-Type: image/png
Last-Modified: Thu, 10 Mar 2011 06:13:43 GMT
Accept-Ranges: bytes
ETag: "c434b24eeadecb1:0"
Date: Mon, 14 Mar 2011 16:08:02 GMT
Connection: close

从中我们可以看到文件大小为16542字节('Content-Length'),服务器支持字节范围('Accept-Ranges: bytes')。

【讨论】:

  • 所以大小为65535字节的文件可以分成5个缓冲区= 13107这是否意味着每个缓冲区的范围将是req = urllib2.Request(url, headers={'Range':'bytes=0-13107'})req2 = urllib2.Request(url, headers={'Range':'bytes=13108-26214'})req3 = urllib2.Request(url, headers={'Range':'bytes=26215-39321'})req4 = urllib2.Request(url, headers={'Range':'bytes=39322-52429'})@ 987654331@ 如果是,我如何使用data = urllib2.urlopen(req).read() 将它们放在一起?
  • @san,一种简单的方法是启动 5 个线程,每个线程调用 urlopen().read() 获取范围并将结果存储在线程安全容器中(列表或字典将在这种情况下做)。然后在主线程中等待这些线程完成(join())并组合部分。
  • 这就是问题所在,我该如何组合零件?
  • @san:只需将它们加在一起,确保它们按顺序排列(通过存储每个部分的起始偏移量并根据它对它们进行排序。)
  • 我有点不确定,{'Range':'bytes=0-13107'}) 的范围是否必须以 0 或 1 开头?考虑到前几个字节可能包含带有必要信息的文件头,我不想丢失或损坏文件!!!
【解决方案2】:

PycURL 可以做到。 PycURL 是 libcurl 的 Python 接口。它可用于从 Python 程序中获取由 URL 标识的对象,类似于 urllib Python 模块。 PycURL 成熟,速度非常快,并且支持很多特性。

【讨论】:

  • 好的,它是如何回答问题的??
猜你喜欢
  • 2018-11-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-28
  • 2019-01-30
相关资源
最近更新 更多