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基本数据类型详细介绍
Mar 11 Python
Python获取电脑硬件信息及状态的实现方法
Aug 29 Python
Python中的pprint折腾记
Jan 21 Python
Python入门之modf()方法的使用
May 15 Python
解决python文件字符串转列表时遇到空行的问题
Jul 09 Python
人机交互程序 python实现人机对话
Nov 14 Python
PyCharm设置SSH远程调试的方法
Jul 17 Python
Python matplotlib的使用并自定义colormap的方法
Dec 13 Python
python实现按首字母分类查找功能
Oct 31 Python
使用PyTorch训练一个图像分类器实例
Jan 08 Python
Python中zipfile压缩文件模块的基本使用教程
Jun 14 Python
只需要100行Python代码就可以实现的贪吃蛇小游戏
May 27 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 缓冲的免费实现方法
2006/10/09 PHP
PHP之数组学习
2011/05/29 PHP
php 面试碰到过的问题 在此做下记录
2011/06/09 PHP
str_replace只替换一次字符串的方法
2013/04/09 PHP
php简单判断两个字符串是否相等的方法
2015/07/13 PHP
PHP fopen函数用法实例讲解
2019/02/15 PHP
浅谈PHP无限极分类原理
2019/03/14 PHP
关于使用runtimeStyle属性问题讨论文章
2007/03/08 Javascript
用jquery与css打造个性化的单选框和复选框
2010/10/20 Javascript
基于jquery的回到页面顶部按钮
2011/06/27 Javascript
JS+CSS 制作的超级简单的下拉菜单附图
2013/11/22 Javascript
jQuery中:nth-child选择器用法实例
2014/12/31 Javascript
javascript实现网页中涉及的简易运动(改变宽高、透明度、位置)
2015/11/29 Javascript
基于javascript代码实现通过点击图片显示原图片
2015/11/29 Javascript
基于jquery实现简单的分页控件
2016/03/17 Javascript
JS在浏览器中解析Base64编码图像
2017/02/09 Javascript
js面向对象编程总结
2017/02/16 Javascript
jQuery 添加样式属性的优先级别方法(推荐)
2017/06/08 jQuery
微信小程序swiper组件用法实例分析【附源码下载】
2017/12/07 Javascript
解决vue组件props传值对象获取不到的问题
2019/06/06 Javascript
[02:44]重置世界,颠覆未来——DOTA2 7.23版本震撼上线
2019/12/01 DOTA
利用Python如何实现数据驱动的接口自动化测试
2018/05/11 Python
python如何发布自已pip项目的方法步骤
2018/10/09 Python
python数据分析:关键字提取方式
2020/02/24 Python
python主要用于哪些方向
2020/07/05 Python
稀有和绝版书籍:Biblio.com
2017/02/02 全球购物
比利时网上药店: Drogisterij.net
2017/03/17 全球购物
澳大利亚波西米亚风情网上商店:Czarina
2019/03/18 全球购物
声明struct x1 { . . . }; 和typedef struct { . . . }x2;有什么不同
2012/06/02 面试题
银行简历自我评价
2014/02/11 职场文书
《美丽的小路》教学反思
2014/02/26 职场文书
纪检干部先进事迹材料
2014/08/23 职场文书
中华魂放飞梦想演讲稿
2014/08/26 职场文书
学校领导班子四风问题整改意见
2014/10/02 职场文书
倡议书的格式写法
2015/04/28 职场文书
redis限流的实际应用
2021/04/24 Redis