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操作Word批量生成文章的方法
Jul 28 Python
Python 类与元类的深度挖掘 I【经验】
May 06 Python
Python中import机制详解
Nov 14 Python
浅析python协程相关概念
Jan 20 Python
Python实现Kmeans聚类算法
Jun 10 Python
使用Python的Django和layim实现即时通讯的方法
May 25 Python
python判断一个对象是否可迭代的例子
Jul 22 Python
django 扩展user用户字段inlines方式
Mar 30 Python
python实现控制台输出彩色字体
Apr 05 Python
Keras之fit_generator与train_on_batch用法
Jun 17 Python
python中绕过反爬虫的方法总结
Nov 25 Python
浅谈哪个Python库才最适合做数据可视化
Jun 28 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 self与$this的详解
2013/06/08 PHP
php通过exif_read_data函数获取图片的exif信息
2015/05/21 PHP
php微信公众号开发之校园图书馆
2018/10/20 PHP
php中加密解密DES类的简单使用方法示例
2020/03/26 PHP
js鼠标滑轮滚动事件绑定的简单实例(兼容主流浏览器)
2014/01/14 Javascript
jQuery中hasClass()方法用法实例
2015/01/06 Javascript
解决Jquery向页面append新元素之后事件的绑定问题
2015/03/16 Javascript
jquery+正则实现统一的表单验证
2015/09/20 Javascript
使用jquery实现鼠标滑过弹出更多相关信息层附源码下载
2015/11/23 Javascript
js实现界面向原生界面发消息并跳转功能
2016/11/22 Javascript
详解react-router如何实现按需加载
2017/06/15 Javascript
使用npm安装最新版本nodejs
2018/01/18 NodeJs
JS获取input[file]的值并显示在页面的实现方法
2018/03/09 Javascript
React性能优化系列之减少props改变的实现方法
2019/01/17 Javascript
vue实现tab栏点击高亮效果
2020/08/19 Javascript
[00:17]DOTA2荣耀之路5:It’s a disastah!
2018/05/28 DOTA
[01:16:12]完美世界DOTA2联赛PWL S2 FTD vs Inki 第一场 11.21
2020/11/23 DOTA
python实现每次处理一个字符的三种方法
2014/10/09 Python
Python实现批量将word转html并将html内容发布至网站的方法
2015/07/14 Python
Python中常见的异常总结
2018/02/20 Python
Python3 pandas 操作列表实例详解
2019/09/23 Python
如何基于Python + requests实现发送HTTP请求
2020/01/13 Python
Python基础类继承重写实现原理解析
2020/04/03 Python
使用Python合成图片的实现代码(图片添加个性化文本,图片上叠加其他图片)
2020/04/30 Python
keras model.fit 解决validation_spilt=num 的问题
2020/06/19 Python
深入了解Python 方法之类方法 & 静态方法
2020/08/17 Python
Html5原生拖拽相关事件简介以及基础实现
2020/11/19 HTML / CSS
MCAKE蛋糕官方网站:一直都是巴黎的味道
2018/02/06 全球购物
啤酒销售实习自我鉴定
2013/09/24 职场文书
会计找工作求职信范文
2013/12/09 职场文书
2014年入党积极分子党课学习心得体会模板
2014/04/03 职场文书
井冈山红色之旅心得体会
2014/10/07 职场文书
党员教师学习党的群众路线教育实践活动心得体会
2014/10/31 职场文书
大学宣传委员竞选稿
2015/11/19 职场文书
心得体会格式及范文
2016/01/25 职场文书
《堡垒之夜》联动《刺客信条》 4月7日正式上线
2022/04/06 其他游戏