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 CGI脚本的教程
Jun 29 Python
Python字典数据对象拆分的简单实现方法
Dec 05 Python
python 信息同时输出到控制台与文件的实例讲解
May 11 Python
利用Pandas读取文件路径或文件名称包含中文的csv文件方法
Jul 04 Python
Python for循环中的陷阱详解
Jul 13 Python
Django admin model 汉化显示文字的实现方法
Aug 12 Python
线程安全及Python中的GIL原理分析
Oct 29 Python
Django后端发送小程序微信模板消息示例(服务通知)
Dec 17 Python
利用python实现逐步回归
Feb 24 Python
python GUI库图形界面开发之PyQt5中QMainWindow, QWidget以及QDialog的区别和选择
Feb 26 Python
如何理解python面向对象编程
Jun 01 Python
Django框架中模型的用法
Jun 10 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中运用http调用的GET和POST方法示例
2014/09/29 PHP
Yii2中YiiBase自动加载类、引用文件方法分析(autoload)
2016/07/25 PHP
如何判断php mysqli扩展类是否开启
2016/12/24 PHP
Discuz! 6.1_jQuery兼容问题
2008/09/23 Javascript
纯JavaScript实现HTML5 Canvas六种特效滤镜示例
2013/06/28 Javascript
javascript对下拉列表框(select)的操作实例讲解
2013/11/29 Javascript
Javascript 按位取反运算符 (~)
2014/02/04 Javascript
使用变量动态设置js的属性名
2014/10/19 Javascript
一个php+js实时显示时间问题
2015/10/12 Javascript
使用contextMenu插件实现Bootstrap table弹出右键菜单
2017/02/20 Javascript
Angular中自定义Debounce Click指令防止重复点击
2017/07/26 Javascript
hammer.js实现图片手势放大效果
2017/08/29 Javascript
Python中用于返回绝对值的abs()方法
2015/05/14 Python
Python中json格式数据的编码与解码方法详解
2016/07/01 Python
Python实现的微信公众号群发图片与文本消息功能实例详解
2017/06/30 Python
详解用TensorFlow实现逻辑回归算法
2018/05/02 Python
Python实现读取SQLServer数据并插入到MongoDB数据库的方法示例
2018/06/09 Python
python 将json数据提取转化为txt的方法
2018/10/26 Python
Python获取当前脚本文件夹(Script)的绝对路径方法代码
2019/08/27 Python
python set集合使用方法解析
2019/11/05 Python
Python实现隐马尔可夫模型的前向后向算法的示例代码
2019/12/31 Python
python 追踪except信息方式
2020/04/25 Python
Python识别处理照片中的条形码
2020/11/16 Python
CSS3之多背景background使用示例
2013/10/18 HTML / CSS
详解快速开发基于 HTML5 网络拓扑图应用
2018/01/08 HTML / CSS
清除canvas画布内容(点擦除+线擦除)
2020/08/12 HTML / CSS
日本著名的服饰鞋帽综合类购物网站:MAGASEEK
2019/01/09 全球购物
网络工程师职业规划
2014/02/10 职场文书
诚信考试标语
2014/06/24 职场文书
表扬稿格式范文
2015/01/16 职场文书
药品销售内勤岗位职责
2015/04/13 职场文书
劳动者解除劳动合同通知书
2015/04/16 职场文书
2016年4月份红领巾广播稿
2015/12/21 职场文书
2016年度继续教育学习心得体会
2016/01/19 职场文书
python实现A*寻路算法
2021/06/13 Python
世界各国短波电台对东亚播送时间频率表(SW)
2021/06/28 无线电