如何将http响应划分为块?

时间:2016-09-22 16:43:57

标签: python multithreading python-3.x urllib downloading

我正在尝试使用python创建一个多线程下载器。假设我有一个大小为100MB的视频的链接,我想使用5个线程下载它,每个线程同时下载20MB。为了实现这一点,我必须将初始响应分为5个部分,代表文件的不同部分(如0-20MB,20-40MB,40-60MB,60-80MB,80-100MB),我搜索并找到了http范围标题可能有帮助。 这是示例代码

   <!DOCTYPE html>
    <html>
    <style>
    body {
        margin: 0;
        font-family: 'Lato', sans-serif;
    }
    
    .overlay {
        height: 0%;
        width: 100%;
        position: fixed;
        z-index: 1;
        top: 0;
        left: 0;
        background-color: rgb(0,0,0);
        background-color: rgba(0,0,0, 0.6);
        overflow-y: hidden;
        transition: 0.5s;
    }
    
    .overlay-content {
        position: relative;
        top: 25%;
        width: 100%;
        text-align: center;
        margin-top: 30px;
    }
    
    .overlay a {
        padding: 8px;
        text-decoration: none;
        font-size: 36px;
        color: #818181;
        display: block;
        transition: 0.3s;
    }
    
    .overlay a:hover, .overlay a:focus {
        color: #f1f1f1;
    }
    
    .overlay .closebtn {
        position: absolute;
        top: 20px;
        right: 45px;
        font-size: 60px;
    }
    
    @media screen and (max-height: 450px) {
      .overlay {overflow-y: auto;}
      .overlay a {font-size: 20px}
      .overlay .closebtn {
        font-size: 40px;
        top: 15px;
        right: 35px;
      }
    }
    </style>
    <body>
    
    <div id="myNav" class="overlay">
      <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
      <div class="overlay-content">
        <a href="#">About</a>
        <a href="#">Services</a>
        <a href="#">Clients</a>
        <a href="#">Contact</a>
      </div>
    </div>
    
    <h2></h2>
    
    <span style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776; open</span>
    
    <script>
    function openNav() {
        document.getElementById("myNav").style.height = "100%";
    }
    
    function closeNav() {
        document.getElementById("myNav").style.height = "0%";
    }
    </script>
         
    </body>
    </html>

但是上面的代码是读取整个视频而不是我想要的字节,它显然无法正常工作。那么有没有办法在视频的任何部分读取指定的字节范围而不是从头开始读取?请尝试用简单的词语解释。

1 个答案:

答案 0 :(得分:1)

  

但上面的代码是读取整个视频而不是字节I.   想要它显然不起作用。

核心问题是默认请求使用 HTTP GET 方法,该方法一次性下拉整个文件。

可以通过添加request.get_method = lambda : 'HEAD'来解决此问题。这使用 HTTP HEAD 方法来获取 Content-Length 并验证是否支持范围请求。

以下是分块请求的工作示例。只需将 url 更改为您感兴趣的网址:

from urllib.request import urlopen, Request

url = 'http://www.jython.org' # This is an example. Use your own url here.

n = 5
request = Request(url)
request.get_method = lambda : 'HEAD'
r = urlopen(request)

# Verify that the server supports Range requests
assert r.headers.get('Accept-Ranges', '') == 'bytes', 'Range requests not supported'

# Compute chunk size using a double negation for ceiling division
total_size = int(r.headers.get('Content-Length'))
chunk_size = -(-total_size // n)

# Showing chunked downloads.  This should be run in multiple threads.
chunks = []
for i in range(n):
    start = i * chunk_size
    end = start + chunk_size - 1  # Bytes ranges are inclusive
    headers = dict(Range = 'bytes=%d-%d' % (start, end))
    request = Request(url, headers=headers)
    chunk = urlopen(request).read()
    chunks.append(chunk)

for循环中的单独请求可以使用线程或进程并行完成。当在具有多个互联网物理连接的环境中运行时,这将提供良好的加速。但是,如果你只有一个物理连接,这可能是瓶颈,那么并行请求将无法像预期的那样有用。