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三元运算符实现方法
Dec 17 Python
Python中Selenium模拟JQuery滑动解锁实例
Jul 26 Python
Python3 处理JSON的实例详解
Oct 29 Python
使用python实现ANN
Dec 20 Python
Python实现批量读取图片并存入mongodb数据库的方法示例
Apr 02 Python
python实现在pandas.DataFrame添加一行
Apr 04 Python
在cmd命令行里进入和退出Python程序的方法
May 12 Python
Python 面向对象之封装、继承、多态操作实例分析
Nov 21 Python
Python 实现一个计时器
Jul 28 Python
Pycharm的Available Packages为空的解决方法
Sep 18 Python
Python 排序最长英文单词链(列表中前一个单词末字母是下一个单词的首字母)
Dec 14 Python
Python通用验证码识别OCR库ddddocr的安装使用教程
Jul 07 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
哪吒敖丙传:新人物二哥敖乙出场 小敖丙奶气十足
2020/03/08 国漫
解决File size limit exceeded 错误的方法
2013/06/14 PHP
php更新修改excel中的内容实例代码
2014/02/26 PHP
ThinkPHP3.1.3版本新特性概述
2014/06/19 PHP
php通过PHPExcel导入Excel表格到MySQL数据库的简单实例
2016/10/29 PHP
详解Laravel设置多态关系模型别名的方式
2019/10/17 PHP
Extjs NumberField后面加单位实现思路
2013/07/30 Javascript
JavaScript实现多维数组的方法
2013/11/20 Javascript
js中setTimeout()与clearTimeout()用法实例浅析
2015/05/12 Javascript
BootStrap Datepicker 插件修改为默认中文的实现方法
2017/02/10 Javascript
React + webpack 环境配置的方法步骤
2017/09/07 Javascript
发布一款npm包帮助理解npm的使用
2019/01/03 Javascript
ES6 Promise对象的含义和基本用法分析
2019/06/14 Javascript
jQuery 常用特效实例小结【显示与隐藏、淡入淡出、滑动、动画等】
2020/05/19 jQuery
pymssql数据库操作MSSQL2005实例分析
2015/05/25 Python
Python实现Windows上气泡提醒效果的方法
2015/06/03 Python
利用django如何解析用户上传的excel文件
2017/07/24 Python
python用户评论标签匹配的解决方法
2018/05/31 Python
解决python中画图时x,y轴名称出现中文乱码的问题
2019/01/29 Python
django框架模型层功能、组成与用法分析
2019/07/30 Python
scrapy利用selenium爬取豆瓣阅读的全步骤
2020/09/20 Python
纯DOM+CSS3实现简单的小风车动画
2016/09/27 HTML / CSS
Canvas绘制浮动球效果的示例
2017/12/29 HTML / CSS
与世界上最好的跑步专业品牌合作:Fleet Feet
2019/03/22 全球购物
德国在线购买葡萄酒网站:Geile Weine
2019/09/24 全球购物
学校安全检查制度
2014/01/27 职场文书
农民工工资承诺书范文
2014/03/31 职场文书
服装设计专业求职信
2014/06/16 职场文书
推广普通话标语
2014/06/27 职场文书
2014党员自我评议表范文
2014/09/20 职场文书
先进个人申报材料
2014/12/30 职场文书
售票员岗位职责
2015/02/15 职场文书
金榜题名主持词
2015/07/02 职场文书
委托开发合同书(标准版)
2019/08/07 职场文书
mysql timestamp比较查询遇到的坑及解决
2021/11/27 MySQL
Spring Boot 使用 Spring-Retry 进行重试框架
2022/04/24 Java/Android