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构造icmp echo请求和实现网络探测器功能代码分享
Jan 10 Python
python3实现ftp服务功能(服务端 For Linux)
Mar 24 Python
python 生成图形验证码的方法示例
Nov 11 Python
python3.4+pycharm 环境安装及使用方法
Jun 13 Python
对python中的装包与解包实例详解
Aug 24 Python
使用Python来做一个屏幕录制工具的操作代码
Jan 18 Python
pycharm 更改创建文件默认路径的操作
Feb 15 Python
Python利用PyPDF2库获取PDF文件总页码实例
Apr 03 Python
Python实现寻找回文数字过程解析
Jun 09 Python
python如何随机生成高强度密码
Aug 19 Python
python爬取代理IP并进行有效的IP测试实现
Oct 09 Python
Python实现对齐打印 format函数的用法
Apr 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
将OICQ数据转成MYSQL数据
2006/10/09 PHP
php数组函数序列之krsort()- 对数组的元素键名进行降序排序,保持索引关系
2011/11/02 PHP
探讨php define()函数及defined()函数使用详解
2013/06/09 PHP
php中使用gd库实现远程图片下载实例
2015/05/12 PHP
PHP基于PDO实现的SQLite操作类【包含增删改查及事务等操作】
2017/06/21 PHP
jtable列中自定义button示例代码
2013/11/21 Javascript
纯javascript实现分页(两种方法)
2015/08/26 Javascript
jquery实现拖动效果(代码分享)
2017/01/25 Javascript
vue-resource 拦截器(interceptor)的使用详解
2017/07/04 Javascript
JavaScript实现图片拖曳效果
2017/09/08 Javascript
JavaScript使用atan2来绘制箭头和曲线的实例
2017/09/14 Javascript
vuex的使用及持久化state的方式详解
2018/01/23 Javascript
Vue实现点击后文字变色切换方法
2018/02/11 Javascript
详解django模板与vue.js冲突问题
2019/07/07 Javascript
解决layui表格内文本超出隐藏的问题
2019/09/12 Javascript
原生JS实现顶部导航栏显示按钮+搜索框功能
2019/12/25 Javascript
前端开发基础javaScript的六大作用
2020/08/06 Javascript
[37:22]DOTA2上海特级锦标赛D组资格赛#2 Liquid VS VP第一局
2016/02/28 DOTA
[00:36]我的中国心——Serenity vs Fnatic
2018/08/21 DOTA
Python translator使用实例
2008/09/06 Python
python使用pyqt写带界面工具的示例代码
2017/10/23 Python
在python中使用正则表达式查找可嵌套字符串组
2017/10/24 Python
Python实现PS图像调整黑白效果示例
2018/01/25 Python
浅谈python写入大量文件的问题
2018/11/09 Python
Python列表切片常用操作实例解析
2020/03/10 Python
Python参数传递机制传值和传引用原理详解
2020/05/22 Python
html5摇一摇代码优化包括DeviceMotionEvent等等
2014/09/01 HTML / CSS
html5手机端页面可以向右滑动导致样式受影响的问题
2018/06/20 HTML / CSS
法国美发器材和产品购物网站:Beauty Coiffure
2016/12/05 全球购物
100%法国制造的游戏和玩具:Les Jouets Français
2021/03/02 全球购物
商务日语专业毕业生求职信
2013/10/26 职场文书
会计实习自我鉴定
2013/12/04 职场文书
决定成败的关键——创业计划书
2014/01/24 职场文书
小学教师读书活动总结
2014/07/08 职场文书
四风之害观后感
2015/06/09 职场文书
2016三八妇女节慰问信
2015/11/30 职场文书