Python实现多线程下载文件的代码实例


Posted in Python onJune 01, 2014

实现简单的多线程下载,需要关注如下几点:
1.文件的大小:可以从reponse header中提取,如“Content-Length:911”表示大小是911字节
2.任务拆分:指定各个线程下载的文件的哪一块,可以通过request header中添加“Range: bytes=300-400”(表示下载300~400byte的内容),注意可以请求的文件的range是[0, size-1]字节的。
3.下载文件的聚合:各个线程将自己下载的文件块保存为临时文件,所有线程都完成后,再将这些临时文件按顺序聚合写入到最终的一个文件中。

实现代码:

#!/usr/bin/python
# -*- coding: utf-8 -*-
# filename: paxel.py
# FROM: http://3water.com/code/view/58/full/
# Jay modified it a little and save for further potential usage.'''It is a multi-thread downloading tool
    It was developed following axel.
        Author: volans
        E-mail: volansw [at] gmail.com
'''
import sys
import os
import time
import urllib
from threading import Thread
# in case you want to use http_proxy
local_proxies = {'http': 'http://131.139.58.200:8080'}
 
class AxelPython(Thread, urllib.FancyURLopener):
    '''Multi-thread downloading class.
        run() is a vitural method of Thread.
    '''
    def __init__(self, threadname, url, filename, ranges=0, proxies={}):
        Thread.__init__(self, name=threadname)
        urllib.FancyURLopener.__init__(self, proxies)
        self.name = threadname
        self.url = url
        self.filename = filename
        self.ranges = ranges
        self.downloaded = 0
    def run(self):
        '''vertual function in Thread'''
        try:
            self.downloaded = os.path.getsize(self.filename)
        except OSError:
            #print 'never downloaded'
            self.downloaded = 0
        # rebuild start poind
        self.startpoint = self.ranges[0] + self.downloaded
        # This part is completed
        if self.startpoint >= self.ranges[1]:
            print 'Part %s has been downloaded over.' % self.filename
            return
        self.oneTimeSize = 16384  # 16kByte/time
        print 'task %s will download from %d to %d' % (self.name, self.startpoint, self.ranges[1])
        self.addheader("Range", "bytes=%d-%d" % (self.startpoint, self.ranges[1]))
        self.urlhandle = self.open(self.url)
        data = self.urlhandle.read(self.oneTimeSize)
        while data:
            filehandle = open(self.filename, 'ab+')
            filehandle.write(data)
            filehandle.close()
            self.downloaded += len(data)
            #print "%s" % (self.name)
            #progress = u'\r...'
            data = self.urlhandle.read(self.oneTimeSize)
 
def GetUrlFileSize(url, proxies={}):
    urlHandler = urllib.urlopen(url, proxies=proxies)
    headers = urlHandler.info().headers
    length = 0
    for header in headers:
        if header.find('Length') != -1:
            length = header.split(':')[-1].strip()
            length = int(length)
    return length
 
def SpliteBlocks(totalsize, blocknumber):
    blocksize = totalsize / blocknumber
    ranges = []
    for i in range(0, blocknumber - 1):
        ranges.append((i * blocksize, i * blocksize + blocksize - 1))
    ranges.append((blocksize * (blocknumber - 1), totalsize - 1))
    return ranges
 
def islive(tasks):
    for task in tasks:
        if task.isAlive():
            return True
    return False
 
def paxel(url, output, blocks=6, proxies=local_proxies):
    ''' paxel
    '''
    size = GetUrlFileSize(url, proxies)
    ranges = SpliteBlocks(size, blocks)
    threadname = ["thread_%d" % i for i in range(0, blocks)]
    filename = ["tmpfile_%d" % i for i in range(0, blocks)]
    tasks = []
    for i in range(0, blocks):
        task = AxelPython(threadname[i], url, filename[i], ranges[i])
        task.setDaemon(True)
        task.start()
        tasks.append(task)
    time.sleep(2)
    while islive(tasks):
        downloaded = sum([task.downloaded for task in tasks])
        process = downloaded / float(size) * 100
        show = u'\rFilesize:%d Downloaded:%d Completed:%.2f%%' % (size, downloaded, process)
        sys.stdout.write(show)
        sys.stdout.flush()
        time.sleep(0.5)
    filehandle = open(output, 'wb+')
    for i in filename:
        f = open(i, 'rb')
        filehandle.write(f.read())
        f.close()
        try:
            os.remove(i)
            pass
        except:
            pass
    filehandle.close()
if __name__ == '__main__':
    url = 'http://dldir1.qq.com/qqfile/QQforMac/QQ_V3.1.1.dmg'
    output = 'download.file'
    paxel(url, output, blocks=4, proxies={})
Python 相关文章推荐
python的id()函数解密过程
Dec 25 Python
跟老齐学Python之大话题小函数(1)
Oct 10 Python
日常整理python执行系统命令的常见方法(全)
Oct 22 Python
Python的Django REST框架中的序列化及请求和返回
Apr 11 Python
使用Python爬了4400条淘宝商品数据,竟发现了这些“潜规则”
Mar 23 Python
python多线程之事件Event的使用详解
Apr 27 Python
Python图像处理之图像的缩放、旋转与翻转实现方法示例
Jan 04 Python
django配置连接数据库及原生sql语句的使用方法
Mar 03 Python
python ChainMap的使用和说明详解
Jun 11 Python
Keras中 ImageDataGenerator函数的参数用法
Jul 03 Python
10个示例带你掌握python中的元组
Nov 23 Python
python中spy++的使用超详细教程
Jan 29 Python
python使用在线API查询IP对应的地理位置信息实例
Jun 01 #Python
pip 错误unused-command-line-argument-hard-error-in-future解决办法
Jun 01 #Python
2款Python内存检测工具介绍和使用方法
Jun 01 #Python
使用Python的Supervisor进行进程监控以及自动启动
May 29 #Python
python应用程序在windows下不出现cmd窗口的办法
May 29 #Python
python正则表达式re模块详细介绍
May 29 #Python
在python中的socket模块使用代理实例
May 29 #Python
You might like
PHP中error_reporting()用法详解
2015/08/31 PHP
详解PHP序列化反序列化的方法
2015/10/27 PHP
分享50个提高PHP执行效率的技巧
2015/12/26 PHP
PHP数组去重比较快的实现方式
2016/01/19 PHP
PHP下载文件函数与用法示例
2019/09/27 PHP
让网页根据不同IE版本显示不同的内容
2009/02/08 Javascript
非常棒的10款jQuery 幻灯片插件
2011/06/14 Javascript
JavaScript 事件入门知识
2015/04/13 Javascript
javascript图片延迟加载实现方法及思路
2015/12/31 Javascript
JavaScript闭包实例详解
2016/06/03 Javascript
AngularJS ng-bind-html 指令详解及实例代码
2016/07/30 Javascript
详解nodejs 文本操作模块-fs模块(五)
2016/12/23 NodeJs
原生JS实现简单放大镜效果
2017/02/08 Javascript
jQuery序列化后的表单值转换成Json
2017/06/16 jQuery
nodejs结合Socket.IO实现的即时通讯功能详解
2018/01/12 NodeJs
Node+OCR实现图像文字识别功能
2018/11/26 Javascript
ES6学习笔记之字符串、数组、对象、函数新增知识点实例分析
2020/01/22 Javascript
JavaScript享元模式原理与用法实例详解
2020/03/09 Javascript
一篇文章带你从零快速上手Rollup
2020/09/07 Javascript
如何在vue中使用百度地图添加自定义覆盖物(水波纹)
2020/11/03 Javascript
使用python实现正则匹配检索远端FTP目录下的文件
2015/03/25 Python
用python做一个搜索引擎(Pylucene)的实例代码
2017/07/05 Python
Python爬虫之urllib基础用法教程
2019/10/12 Python
Python实现微信好友的数据分析
2019/12/16 Python
python实现AdaBoost算法的示例
2020/10/03 Python
用css3制作纸张效果(外翻卷角)
2013/02/01 HTML / CSS
使用SVG实现提示框功能的示例代码
2020/06/05 HTML / CSS
灵泰克Java笔试题
2016/01/09 面试题
教师的实习鉴定
2013/12/15 职场文书
护理专业毕业生自荐信范文
2014/01/05 职场文书
考试作弊检讨书大全
2014/02/18 职场文书
交通事故协议书范文
2014/04/16 职场文书
基层党员对照检查材料
2014/09/24 职场文书
综合办公室主任岗位职责
2015/04/01 职场文书
亮剑观后感600字
2015/06/05 职场文书
《学会看病》教学反思
2016/02/17 职场文书