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 相关文章推荐
Java中重定向输出流实现用文件记录程序日志
Jun 12 Python
python 3.0 模拟用户登录功能并实现三次错误锁定
Nov 01 Python
老生常谈python中的重载
Nov 11 Python
Python2和Python3中urllib库中urlencode的使用注意事项
Nov 26 Python
Python静态类型检查新工具之pyright 使用指南
Apr 26 Python
使用OpenCV实现仿射变换—平移功能
Aug 29 Python
Python流程控制 while循环实现解析
Sep 02 Python
Python3实现监控新型冠状病毒肺炎疫情的示例代码
Feb 13 Python
django实现后台显示媒体文件
Apr 07 Python
Pytorch转keras的有效方法,以FlowNet为例讲解
May 26 Python
pytorch MSELoss计算平均的实现方法
May 12 Python
pycharm 如何查看某一函数源码的快捷键
May 12 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实现验证码功能
2006/10/09 PHP
一个ORACLE分页程序,挺实用的.
2006/10/09 PHP
让你的WINDOWS同时支持MYSQL4,MYSQL4.1,MYSQL5X
2006/12/06 PHP
利用php实现禁用IE和火狐的缓存问题
2012/12/03 PHP
Laravel模板引擎Blade中section的一些标签的区别介绍
2015/02/10 PHP
php 如何设置一个严格控制过期时间的session
2017/05/05 PHP
javascript最常用与实用的创建类的代码
2010/08/12 Javascript
JavaScript中的排序算法代码
2011/02/22 Javascript
javascript中数组的冒泡排序使用示例
2013/12/18 Javascript
ExtJS中设置下拉列表框不可编辑的方法
2014/05/07 Javascript
JavaScript中定义函数的三种方法
2015/03/12 Javascript
浅析JavaScript的几种Math函数,random(),ceil(),round(),floor()
2016/12/22 Javascript
bootstrap配合Masonry插件实现瀑布式布局
2017/01/18 Javascript
js实现3d悬浮效果
2017/02/16 Javascript
bootstrap模态框远程示例代码分享
2017/05/22 Javascript
详解vue移动端日期选择组件
2018/02/22 Javascript
10个最受欢迎的 JavaScript框架(推荐)
2019/04/24 Javascript
JavaScript中的ES6 Proxy的具体使用
2019/06/16 Javascript
layui实现数据分页功能
2019/07/27 Javascript
python常规方法实现数组的全排列
2015/03/17 Python
基于ID3决策树算法的实现(Python版)
2017/05/31 Python
Python排序搜索基本算法之插入排序实例分析
2017/12/11 Python
python中的迭代和可迭代对象代码示例
2017/12/27 Python
对numpy中array和asarray的区别详解
2018/04/17 Python
基于python的图片修复程序(实现水印去除)
2018/06/04 Python
python获取点击的坐标画图形的方法
2019/07/09 Python
python实现输入的数据在地图上生成热力图效果
2019/12/06 Python
Python3和pyqt5实现控件数据动态显示方式
2019/12/13 Python
基于python实现语音录入识别代码实例
2020/01/17 Python
tensorflow之自定义神经网络层实例
2020/02/07 Python
python和js交互调用的方法
2020/06/23 Python
Python是怎样处理json模块的
2020/07/16 Python
html5 touch事件实现触屏页面上下滑动(一)
2016/03/10 HTML / CSS
互动出版网:专业书籍
2017/03/21 全球购物
学校七一活动方案
2014/01/19 职场文书
Java基于Dijkstra算法实现校园导游程序
2022/03/17 Java/Android