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错误和解决方法汇总整理
Jun 03 Python
Python随手笔记之标准类型内建函数
Dec 02 Python
Tensorflow实现卷积神经网络的详细代码
May 24 Python
django js实现部分页面刷新的示例代码
May 28 Python
Python读取YUV文件,并显示的方法
Dec 04 Python
python利用re,bs4,requests模块获取股票数据
Jul 29 Python
logging level级别介绍
Feb 21 Python
Python3标准库glob文件名模式匹配的问题
Mar 13 Python
基于Python共轭梯度法与最速下降法之间的对比
Apr 02 Python
基于python计算滚动方差(标准差)talib和pd.rolling函数差异详解
Jun 08 Python
python里glob模块知识点总结
Jan 05 Python
python绘制高斯曲线
Feb 19 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
在线短消息收发的程序,不用数据库
2006/10/09 PHP
php之字符串变相相减的代码
2007/03/19 PHP
php使用ftp实现文件上传与下载功能
2017/07/21 PHP
js function定义函数的几种不错方法
2014/02/27 Javascript
node.js不得不说的12点内容
2014/07/14 Javascript
基于jquery实现左右按钮点击的图片切换效果
2021/01/27 Javascript
微信小程序 UI布局常用技巧整理总结
2016/12/05 Javascript
详解springmvc 接收json对象的两种方式
2016/12/06 Javascript
bootstrap按钮插件(Button)使用方法解析
2017/01/13 Javascript
jQuery之动画ajax事件(实例讲解)
2017/07/18 jQuery
基于LayUI实现前端分页功能的方法
2017/07/22 Javascript
ES6模块化的import和export用法方法总结
2017/08/08 Javascript
在vue里使用codemirror遇到的问题
2018/11/01 Javascript
VUE的history模式下除了index外其他路由404报错解决办法
2019/08/21 Javascript
JavaScript实现文件下载并重命名代码实例
2019/12/12 Javascript
一篇文章让你搞懂JavaScript 原型和原型链
2020/11/23 Javascript
[42:20]2014 DOTA2华西杯精英邀请赛5 24 DK VS NewBee
2014/05/25 DOTA
Python中实现常量(Const)功能
2015/01/28 Python
python 第三方库的安装及pip的使用详解
2017/05/11 Python
pandas实现选取特定索引的行
2018/04/20 Python
用python处理MS Word的实例讲解
2018/05/08 Python
Python实现的银行系统模拟程序完整案例
2019/04/12 Python
Python爬虫爬取新闻资讯案例详解
2020/07/14 Python
公认8个效率最高的爬虫框架
2020/07/28 Python
python实现移动木板小游戏
2020/10/09 Python
运行Python编写的程序方法实例
2020/10/21 Python
CSS3系列教程:背景图片(背景大小和多背景图) 应用说明
2012/12/19 HTML / CSS
Casetify官网:自制专属手机壳、iPad护壳和Apple Watch手表带
2018/05/09 全球购物
食品行业求职人的自我评价
2014/01/19 职场文书
大学生毕业鉴定
2014/01/31 职场文书
yy司仪主持词
2014/03/22 职场文书
意外伤害赔偿协议书
2014/09/16 职场文书
2014年煤矿工作总结
2014/11/24 职场文书
2016年高校自主招生自荐信范文
2015/03/24 职场文书
公司搬迁通知
2015/04/20 职场文书
法律讲堂观后感
2015/06/11 职场文书