那个啥
很多年前网际快车很火,多线程,断点续传,前段时间心血来潮想自己实现一个,不知道从哪下手,搜了下python断点续传,和并发下载的blog文章,了解了下。
什么样的文件可以分段下载
根据RFC2616第14.5节的说明,响应头部包含{"Accept-Range":"bytes"}的内容,客户端请求时可以指定范围,籍此实现分段下载。
判断一个文件是否可以分段下载
http请求通常的**method
**通常是GET
和POST
,而HEAD
方法可以只请求头部而不下载文件。aiohttp可以实现完全相同的功能,但是好像对象全是异步的,普通方法没办法驱动,这里用urllib.request演示下
In [19]: import urllib.request as request
In [20]: url ="https://download.alicdn.com/wangwang/AliIM2017_taobao(9.07.03C).exe"
In [22]: req = request.Request(url,method="HEAD")
In [23]: resp = request.urlopen(req)
In [24]: resp.getheaders()
Out[24]:
[('Server', 'Tengine'),
('Content-Type', 'application/octet-stream'),
('Content-Length', '58581976'),
('Connection', 'close'),
('Date', 'Wed, 31 May 2017 04:45:20 GMT'),
('x-oss-request-id', '592E4A60D4279A6C24CED27E'),
('Accept-Ranges', 'bytes'),
]
#为了节约空间删掉了一些也许很有价值的头部信息
通过method='HEAD'
只请求头部,如果出现"Accetp-Ranges":"bytes"
,就表示这个文件支持客户端按范围下载,同时获得需要知道下载文件大小:'Content-Length':'58581976'
。后面我们会假定头部出现"Content-Length"就表示文件支持范围请求,即支持分段下载。
思路
其实整出来并发下载的并不难,分段写入因为知识不够全面花了点时间也算是搞定了,但是涉及续传的和异常处理就有点复杂了,这里罗列出基本步骤,不涉及细节。
- 获取头部长度,按需求列出分片
- 在单个协程内组织写入和读取的方式
- 排定协程,驱动事件执行协程队列。
如何单文件实现断点续传?
这位大神的思路:python编写断点续传下载软件 很简单,判断文件大小就知道写到哪了,下次请求剩余部分即可,但是好像不太适合分片写入的情况,我的想法是,维护一个队列来跟踪下载进度(各区块的完成情况),然后pickle.dumps
为二进制数据,然后写入到文件最大长度之后,再次下载的时候读取文件最大长度之后的部分,pickle.loads
载入下载进度,等文件下载完成以后,seek到文件标定长度truncate截断文件。 现在不太了解的是如何捕获键盘中断
待续,希望不要太监。。。