python多线程http下载实现示例


Posted in Python onDecember 30, 2013

测试平台 Ubuntu 13.04 X86_64 Python 2.7.4

花了将近两个小时, 问题主要刚开始没有想到传一个文件对象到线程里面去, 导致下载下来的文件和源文件MD5不一样,浪费不少时间.

有兴趣的同学可以拿去加上参数,改进下, 也可以加上断点续传.

# -*- coding: utf-8 -*-
# Author: ToughGuy
# Email: wj0630@gmail.com
# 写这玩意儿是为了初步了解下python的多线程机制
# 平时没写注释的习惯, 这次花时间在代码里面写上注释也是希望有问题的地方请各位指正, 因为可能我自己也没弄明白.
# 测试平台 Ubuntu 13.04 X86_64 Python 2.7.4
import threading
import urllib2
import sys
max_thread = 10
# 初始化锁
lock = threading.RLock()
class Downloader(threading.Thread):
    def __init__(self, url, start_size, end_size, fobj, buffer):
        self.url = url
        self.buffer = buffer
        self.start_size = start_size
        self.end_size = end_size
        self.fobj = fobj
        threading.Thread.__init__(self)
    def run(self):
        """
            马甲而已
        """
        with lock:
            print 'starting: %s' % self.getName()
        self._download()
    def _download(self):
        """
            我才是搬砖的
        """
        req = urllib2.Request(self.url)
        # 添加HTTP Header(RANGE)设置下载数据的范围
        req.headers['Range'] = 'bytes=%s-%s' % (self.start_size, self.end_size)
        f = urllib2.urlopen(req)
        # 初始化当前线程文件对象偏移量
        offset = self.start_size
        while 1:
            block = f.read(self.buffer)
            # 当前线程数据获取完毕后则退出
            if not block:
                with lock:
                    print '%s done.' % self.getName()
                break
            # 写如数据的时候当然要锁住线程
            # 使用 with lock 替代传统的 lock.acquire().....lock.release()
            # 需要python >= 2.5
            with lock:
                sys.stdout.write('%s saveing block...' % self.getName())
                # 设置文件对象偏移地址
                self.fobj.seek(offset)
                # 写入获取到的数据
                self.fobj.write(block)
                offset = offset + len(block)
                sys.stdout.write('done.\n')

def main(url, thread=3, save_file='', buffer=1024):
    # 最大线程数量不能超过max_thread
    thread = thread if thread <= max_thread else max_thread
    # 获取文件的大小
    req = urllib2.urlopen(url)
    size = int(req.info().getheaders('Content-Length')[0])
    # 初始化文件对象
    fobj = open(save_file, 'wb')
    # 根据线程数量计算 每个线程负责的http Range 大小
    avg_size, pad_size = divmod(size, thread)
    plist = []
    for i in xrange(thread):
        start_size = i*avg_size
        end_size = start_size + avg_size - 1
        if i == thread - 1:
            # 最后一个线程加上pad_size
            end_size = end_size + pad_size + 1
        t = Downloader(url, start_size, end_size, fobj, buffer)
        plist.append(t)
    #  开始搬砖
    for t in plist:
        t.start()
    # 等待所有线程结束
    for t in plist:
        t.join()
    # 结束当然记得关闭文件对象
    fobj.close()
    print 'Download completed!'
if __name__ == '__main__':
    url = 'http://192.168.1.2:8082/downloads/10M.zip'
    main(url=url, thread=10, save_file='test.iso', buffer=4096)
Python 相关文章推荐
Python解析json文件相关知识学习
Mar 01 Python
python批量读取txt文件为DataFrame的方法
Apr 03 Python
Python通过调用有道翻译api实现翻译功能示例
Jul 19 Python
说说如何遍历Python列表的方法示例
Feb 11 Python
Python两个字典键同值相加的几种方法
Mar 05 Python
python 一个figure上显示多个图像的实例
Jul 08 Python
Python实现一个数组除以一个数的例子
Jul 20 Python
Python 用matplotlib画以时间日期为x轴的图像
Aug 06 Python
Python 获取项目根路径的代码
Sep 27 Python
Python使用Opencv实现图像特征检测与匹配的方法
Oct 30 Python
python opencv 实现对图像边缘扩充
Jan 19 Python
基于python 等频分箱qcut问题的解决
Mar 03 Python
python正则匹配查询港澳通行证办理进度示例分享
Dec 27 #Python
python模拟登录百度代码分享(获取百度贴吧等级)
Dec 27 #Python
python读文件逐行处理的示例代码分享
Dec 27 #Python
python调用cmd复制文件代码分享
Dec 27 #Python
win7安装python生成随机数代码分享
Dec 27 #Python
python正则匹配抓取豆瓣电影链接和评论代码分享
Dec 27 #Python
python正则表达式去掉数字中的逗号(python正则匹配逗号)
Dec 25 #Python
You might like
如何过滤高亮显示非法字符
2006/10/09 PHP
PHP4实际应用经验篇(2)
2006/10/09 PHP
用PHP为SHOPEX增加日志功能代码
2010/07/02 PHP
php foreach循环中使用引用的问题
2013/11/06 PHP
ThinkPHP中的常用查询语言汇总
2014/08/22 PHP
详解WordPress中的头像缓存和代理中的缓存更新方法
2016/03/01 PHP
javascript 基础篇3 类,回调函数,内置对象,事件处理
2012/03/14 Javascript
jQuery实现简易的天天爱消除小游戏
2015/10/16 Javascript
两种js监听滚轮事件的实现方法
2016/05/13 Javascript
AngularJS 获取ng-repeat动态生成的ng-model值实例详解
2016/11/29 Javascript
Bootstrap实现的经典栅格布局效果实例【附demo源码】
2017/03/30 Javascript
Angular.JS通过指令操作DOM的方法
2017/05/10 Javascript
微信小程序tabBar用法实例详解
2017/12/04 Javascript
关于js对textarea换行符的处理方法浅析
2018/08/03 Javascript
jQuery实现基本动画效果的方法详解
2018/09/06 jQuery
在vue使用clipboard.js进行一键复制文本的实现示例
2019/01/15 Javascript
jQuery AJAX与jQuery事件的分析讲解
2019/02/18 jQuery
layui-table对返回的数据进行转变显示的实例
2019/09/04 Javascript
Vertx基于EventBus发送接受自定义对象
2020/11/16 Javascript
Python操作CouchDB数据库简单示例
2015/03/10 Python
使用PyCharm配合部署Python的Django框架的配置纪实
2015/11/19 Python
Python检测网站链接是否已存在
2016/04/07 Python
使用Selenium破解新浪微博的四宫格验证码
2018/10/19 Python
python获取点击的坐标画图形的方法
2019/07/09 Python
django的csrf实现过程详解
2019/07/26 Python
python实现图像全景拼接
2020/03/27 Python
html5 svg 中元素点击事件添加方法
2013/01/16 HTML / CSS
Black Halo官方网站:购买连衣裙、礼服和连体裤
2018/06/13 全球购物
女大学生自我鉴定
2013/12/09 职场文书
成品仓管员岗位职责
2013/12/11 职场文书
销售人员获奖感言
2014/02/05 职场文书
《台湾的蝴蝶谷》教学反思
2014/02/20 职场文书
离婚协议书怎么写
2014/09/12 职场文书
优秀党员事迹材料
2014/12/18 职场文书
蔬果开业典礼发言稿应该怎么写?
2019/09/03 职场文书
python保存大型 .mat 数据文件报错超出 IO 限制的操作
2021/05/10 Python