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自动化工具日志查询分析脚本代码实现
Nov 26 Python
Python实现简单拆分PDF文件的方法
Jul 30 Python
Django自定义认证方式用法示例
Jun 23 Python
基于python OpenCV实现动态人脸检测
May 25 Python
Python画柱状统计图操作示例【基于matplotlib库】
Jul 04 Python
Python多线程应用于自动化测试操作示例
Dec 06 Python
python实现电子产品商店
Feb 26 Python
python GUI库图形界面开发之PyQt5窗口类QMainWindow详细使用方法
Feb 26 Python
selenium WebDriverWait类等待机制的实现
Mar 18 Python
python文件操作seek()偏移量,读取指正到指定位置操作
Jul 05 Python
Python定时任务框架APScheduler原理及常用代码
Oct 05 Python
讲解Python实例练习逆序输出字符串
May 06 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
用PHP伪造referer突破网盘禁止外连的代码
2008/06/15 PHP
ThinkPHP 模板引擎使用详解
2017/05/07 PHP
phpstorm最新激活码分享亲测phpstorm2020.2.3版可用
2020/11/22 PHP
jquery获取input表单值的代码
2010/04/19 Javascript
fancybox modal的完美解决(右上的X)
2012/10/30 Javascript
javaScript arguments 对象使用介绍
2013/10/18 Javascript
js键盘事件的keyCode
2014/07/29 Javascript
js判断日期时间有效性的方法
2015/10/24 Javascript
基于Jquery代码实现支持PC端手机端幻灯片代码
2015/11/17 Javascript
BootStrap tooltip提示框使用小结
2016/10/26 Javascript
Bootstrap table表格简单操作
2017/02/07 Javascript
JS+HTML5 FileReader对象用法示例
2017/04/07 Javascript
解决vue项目打包后提示图片文件路径错误的问题
2018/07/04 Javascript
解决vue2.0 element-ui中el-upload的before-upload方法返回false时submit()不生效问题
2018/08/24 Javascript
vue使用高德地图根据坐标定位点的实现代码
2019/08/22 Javascript
node.js中path路径模块的使用方法实例分析
2020/02/13 Javascript
使用konva和vue-konva库实现拖拽滑块验证功能
2020/04/27 Javascript
vue Element左侧无限级菜单实现
2020/06/10 Javascript
如何通过Proxy实现JSBridge模块化封装
2020/10/22 Javascript
[01:25]2015国际邀请赛最佳短片奖——斧王《拆塔英雄:天赋异禀》
2015/09/22 DOTA
Python中的赋值、浅拷贝、深拷贝介绍
2015/03/09 Python
python中星号变量的几种特殊用法
2016/09/07 Python
Python中的探索性数据分析(功能式)
2017/12/22 Python
python中logging包的使用总结
2018/02/28 Python
Python Pandas批量读取csv文件到dataframe的方法
2018/10/08 Python
HTML5+CSS3 实现灵动的动画 TAB 切换效果(DEMO)
2017/09/15 HTML / CSS
飞利浦比利时官方网站:Philips比利时
2016/08/24 全球购物
华为智利官方商店:Huawei Chile
2020/05/09 全球购物
七一党建活动方案
2014/01/28 职场文书
安全大检查反思材料
2014/01/31 职场文书
2014年幼儿园后勤工作总结
2014/11/10 职场文书
小学教师见习总结
2015/06/23 职场文书
初中体育教学随笔
2015/08/15 职场文书
php中配置文件保存修改操作 如config.php文件的读取修改等操作
2021/05/12 PHP
pandas中DataFrame重置索引的几种方法
2021/05/24 Python
CSS实现鼠标悬浮动画特效
2023/05/07 HTML / CSS