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中zip()函数用法实例教程
Jul 31 Python
Python中dictionary items()系列函数的用法实例
Aug 21 Python
Python列表(list)常用操作方法小结
Feb 02 Python
使用优化器来提升Python程序的执行效率的教程
Apr 02 Python
Python中的模块导入和读取键盘输入的方法
Oct 16 Python
Python的Django框架中消息通知的计数器实现教程
Jun 13 Python
使用python语言,比较两个字符串是否相同的实例
Jun 29 Python
python的pygal模块绘制反正切函数图像方法
Jul 16 Python
win10子系统python开发环境准备及kenlm和nltk的使用教程
Oct 14 Python
python turtle工具绘制四叶草的实例分享
Feb 14 Python
Python发送邮件实现基础解析
Aug 14 Python
python 实现朴素贝叶斯算法的示例
Sep 30 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中curl_multi的应用
2013/07/17 PHP
js Function类型
2011/12/04 Javascript
JS的document.all函数使用示例
2013/12/30 Javascript
innerText 使用示例
2014/01/23 Javascript
jquery实现焦点图片随机切换效果的方法
2015/03/12 Javascript
浅析JavaScript中的array数组类型系统
2016/07/18 Javascript
js只执行1次的函数示例
2016/07/20 Javascript
关于input全选反选恶心的异常情况
2016/07/24 Javascript
浅谈vue中改elementUI默认样式引发的static与assets的区别
2018/02/03 Javascript
JavaScript 有用的代码片段和 trick
2018/02/22 Javascript
vue.js计算属性computed用法实例分析
2018/07/06 Javascript
node.js爬取中关村的在线电瓶车信息
2018/11/13 Javascript
express+vue+mongodb+session 实现注册登录功能
2018/12/06 Javascript
微信小程序动态添加view组件的实例代码
2019/05/23 Javascript
浅谈Vue使用Cascader级联选择器数据回显中的坑
2020/10/31 Javascript
python根据unicode判断语言类型实例代码
2018/01/17 Python
Linux-ubuntu16.04 Python3.5配置OpenCV3.2的方法
2018/04/02 Python
python中cPickle类使用方法详解
2018/08/27 Python
python scipy卷积运算的实现方法
2019/09/16 Python
Win10+GPU版Pytorch1.1安装的安装步骤
2019/09/27 Python
python中wx模块的具体使用方法
2020/05/15 Python
Python基于内置函数type创建新类型
2020/10/22 Python
Python+OpenCV图像处理—— 色彩空间转换
2020/10/22 Python
佛罗里达州印第安河新鲜水果:Hale Groves
2017/02/20 全球购物
澳大利亚第一的设计师礼服租赁网站:GlamCorner
2017/08/13 全球购物
英国最出名高街品牌:Forever Unique
2018/02/24 全球购物
Nike墨西哥官网:Nike MX
2020/08/30 全球购物
党员个人剖析材料
2014/09/30 职场文书
党的群众路线批评与自我批评发言稿
2014/10/16 职场文书
公司放假通知怎么写
2015/04/15 职场文书
该怎么书写道歉信?
2019/07/03 职场文书
详解PHP设计模式之依赖注入模式
2021/05/25 PHP
使用Djongo模块在Django中使用MongoDB数据库
2021/06/20 Python
SQL Server中常用截取字符串函数介绍
2022/03/16 SQL Server
Elasticsearch 配置详解
2022/04/19 Java/Android
Mysql表数据比较大情况下修改添加字段的方法实例
2022/06/28 MySQL