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里对list中的整数求平均并排序
Sep 12 Python
Python字符串拼接的几种方法整理
Aug 02 Python
PyCharm配置mongo插件的方法
Nov 30 Python
Python基础之文件读取的讲解
Feb 16 Python
一文秒懂python读写csv xml json文件各种骚操作
Jul 04 Python
Django和Flask框架优缺点对比
Oct 24 Python
Python通过递归获取目录下指定文件代码实例
Nov 07 Python
Python简单实现区域生长方式
Jan 16 Python
python 实现在无序数组中找到中位数方法
Mar 03 Python
六种酷炫Python运行进度条效果的实现代码
Jul 17 Python
浅谈对python中if、elif、else的误解
Aug 20 Python
使用python爬取抖音app视频的实例代码
Dec 01 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中的Memcache详解
2014/04/05 PHP
PHP扩展mcrypt实现的AES加密功能示例
2019/01/29 PHP
JavaScript面向对象之Prototypes和继承
2012/07/12 Javascript
浅析JavaScript中的常用算法与函数
2013/11/21 Javascript
javascript的函数作用域
2014/11/12 Javascript
jQuery入门介绍之基础知识
2015/01/13 Javascript
JavaScript正则表达式匹配 div  style标签
2016/03/15 Javascript
微信小程序页面滑动屏幕加载数据效果
2020/11/16 Javascript
JavaScript数组去重的多种方法(四种)
2017/09/19 Javascript
vue源码入口文件分析(推荐)
2018/01/30 Javascript
p5.js绘制创意自画像
2019/11/04 Javascript
Python多线程下载文件的方法
2015/07/10 Python
python xml解析实例详解
2016/11/14 Python
Python正则表达式教程之二:捕获篇
2017/03/02 Python
Python中的defaultdict与__missing__()使用介绍
2018/02/03 Python
pycharm 主题theme设置调整仿sublime的方法
2018/05/23 Python
python基于paramiko将文件上传到服务器代码实现
2019/07/08 Python
详解使用python绘制混淆矩阵(confusion_matrix)
2019/07/14 Python
Pycharm+django2.2+python3.6+MySQL实现简单的考试报名系统
2019/09/05 Python
torch 中各种图像格式转换的实现方法
2019/12/26 Python
浅析Python 责任链设计模式
2020/09/11 Python
意大利领先的奢侈品在线时装零售商:MCLABELS
2020/10/13 全球购物
社团文化节邀请函
2014/01/10 职场文书
社区庆中秋节活动方案
2014/02/07 职场文书
房务中心文员岗位职责
2014/04/16 职场文书
小班下学期评语
2014/05/04 职场文书
大学生村官座谈会发言材料
2014/05/25 职场文书
工资收入证明样本(5篇)
2014/09/16 职场文书
2014年收银工作总结
2014/11/13 职场文书
2014预防青少年违法犯罪工作总结
2014/12/10 职场文书
个人思想政治总结
2015/03/05 职场文书
会计求职信怎么写
2015/03/20 职场文书
悬崖上的金鱼姬观后感
2015/06/15 职场文书
关于应聘教师的自荐信
2016/01/28 职场文书
Python Flask请求扩展与中间件相关知识总结
2021/06/11 Python
Java使用HttpClient实现文件下载
2022/08/14 Java/Android