要以python块的形式下载文件吗?

时间:2020-07-21 06:49:10

标签: python concurrency python-requests http-headers download-manager

我正在编写一个简单的同步下载管理器,该管理器将分10个部分下载视频文件。我正在使用requests从标题中获取内容长度。我正在使用它破坏并下载10个文件。字节块,然后合并它们以形成完整的视频。下面的代码假定可以这种方式工作,但是最终的合并文件只能工作几秒钟,之后它就会损坏。我的代码有什么问题?

import requests
import os

def intervals(parts, duration):
    part_duration = duration // parts
    return [(i * part_duration, (i + 1) * part_duration) for i in range(parts)]

home = os.path.expanduser("~")
if not os.path.exists(home+'/Desktop/temp'):
    os.makedirs(home+'/Desktop/temp')

PATH = home+"/Desktop/temp/tmp.mp4"

example_file_url = "https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_1280_10MG.mp4"


req = requests.head(example_file_url)

size = int(req.headers['Content-Length'])

content_section = 10

section_intervals = intervals(content_section,size)


with  open(PATH, "wb") as file:
    for i,(start,end) in enumerate(section_intervals):
        headers = {"Range": "bytes="+str(start)+"-"+str(end)}
        print(headers)
        r = requests.get(example_file_url, headers=headers)
        file.write(r.content)

1 个答案:

答案 0 :(得分:1)

问题

您的范围是错误的,因为Range标头指定的间隔给出了第一个和最后一个偏移量,例如bytes=0-10表示从0到10的11个字节(与python中的slice不同),因此bytes=0-10bytes=10-20是重叠范围。例如,您将需要bytes=0-9后接bytes=10-19

请参见此documentation中的示例:

请求头1024个字节的标头... Range: bytes=0-1023

(而python slice中的[0:1023]的长度为1023)。

在您说它“可以工作几秒钟,然后损坏”的地方,我想您的意思是它在MP4解码输出的前几秒钟内有效。中断的地方将是第一个下载部分的末尾,其中第一部分的最后一个字节在第二部分的开始处重复。

另一个问题是,您的总长度是错误的,因为您将整数除以parts,然后再乘以整数时,您已经失去了最后的小数部分。

修复

将您的intervals函数更改为此,它可以起作用:

import math

def intervals(parts, duration):
    part_duration = math.ceil(duration / parts)
    return [(start, min(start + part_duration - 1, duration - 1)) 
             for start in range(0, duration, part_duration)]

检查范围

插入打印语句:

print("Size = ", size)
print(section_intervals)

现在给出:

Size =  9840497
[(0, 984049), (984050, 1968099), (1968100, 2952149), (2952150, 3936199), (3936200, 4920249), (4920250, 5904299), (5904300, 6888349), (6888350, 7872399), (7872400, 8856449), (8856450, 9840496)]

使用原始的intervals函数,它可以提供:

Size =  9840497
[(0, 984049), (984049, 1968098), (1968098, 2952147), (2952147, 3936196), (3936196, 4920245), (4920245, 5904294), (5904294, 6888343), (6888343, 7872392), (7872392, 8856441), (8856441, 9840490)]

请注意重叠范围和末尾缺少的字节。

使用md5sum验证输出

我们可以通过计算校验和最终验证下载。在此示例中,我从Linux命令行使用md5sum(尽管cksum也可以工作,因为不需要为此使用密码校验和)。

我将输出称为myoutput

$ md5sum myoutput
10c918b1d01aea85864ee65d9e0c2305  myoutput

现在,我还直接通过wget <url>下载了一个副本,并发现它具有相同的校验和。

$ wget https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_1280_10MG.mp4
--2020-07-21 08:26:52--  https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_1280_10MG.mp4

$ md5sum file_example_MP4_1280_10MG.mp4 
10c918b1d01aea85864ee65d9e0c2305  file_example_MP4_1280_10MG.mp4