Python实现多线程HTTP下载器示例


Posted in Python onFebruary 11, 2017

本文将介绍使用Python编写多线程HTTP下载器,并生成.exe可执行文件。

环境:windows/Linux + Python2.7.x

单线程

在介绍多线程之前首先介绍单线程。编写单线程的思路为:

1.解析url;

2.连接web服务器;

3.构造http请求包;

4.下载文件。

接下来通过代码进行说明。

解析url

通过用户输入url进行解析。如果解析的路径为空,则赋值为'/';如果端口号为空,则赋值为"80”;下载文件的文件名可根据用户的意愿进行更改(输入'y'表示更改,输入其它表示不需要更改)。

下面列出几个解析函数:

#解析host和path
def analyHostAndPath(totalUrl):
  protocol,s1 = urllib.splittype(totalUrl)
  host, path = urllib.splithost(s1)
  if path == '':
    path = '/'
  return host, path

#解析port
def analysisPort(host):
  host, port = urllib.splitport(host)
  if port is None:
    return 80
  return port

#解析filename
def analysisFilename(path):
  filename = path.split('/')[-1]
  if '.' not in filename:
    return None
  return filename

连接web服务器

使用socket模块,根据解析url得到的host和port连接web服务器,代码如下:

import socket
from analysisUrl import port,host

ip = socket.gethostbyname(host)
s = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
s.connect((ip, port))

print "success connected webServer!!"

构造http请求包

根据解析url得到的path, host, port构造一个HTTP请求包。 

from analysisUrl import path, host, port

packet = 'GET ' + path + ' HTTP/1.1\r\nHost: ' + host + '\r\n\r\n' 

下载文件

根据构造的http请求包,向服务器发送文件,抓取响应报文头部的"Content-Length"。 

def getLength(self):
    s.send(packet)
    print "send success!"
    buf = s.recv(1024)
    print buf
    p = re.compile(r'Content-Length: (\d*)')
    length = int(p.findall(buf)[0])
    return length, buf

下载文件并计算下载所用的时间。 

def download(self):
    file = open(self.filename,'wb')
    length,buf = self.getLength()
    packetIndex = buf.index('\r\n\r\n')
    buf = buf[packetIndex+4:]
    file.write(buf)
    sum = len(buf)
    while 1:
      buf = s.recv(1024)
      file.write(buf)
      sum = sum + len(buf)
      if sum >= length:
        break
    print "Success!!"

if __name__ == "__main__":
  start = time.time()
  down = downloader()
  down.download()
  end = time.time()
  print "The time spent on this program is %f s"%(end - start)

多线程

抓取响应报文头部的"Content-Length"字段,结合线程个数,加锁分段下载。与单线程的不同,这里将所有代码整合为一个文件,代码中使用更多的Python自带模块。

得到"Content-Length":

def getLength(self):
    opener = urllib2.build_opener()
    req = opener.open(self.url)
    meta = req.info()
    length = int(meta.getheaders("Content-Length")[0])
    return length

根据得到的Length,结合线程个数划分范围:

def get_range(self):
    ranges = []
    length = self.getLength()
    offset = int(int(length) / self.threadNum)
    for i in range(self.threadNum):
      if i == (self.threadNum - 1):
        ranges.append((i*offset,''))
      else:
        ranges.append((i*offset,(i+1)*offset))
    return ranges

实现多线程下载,在向文件写入内容时,向线程加锁,并使用with lock代替lock.acquire( )...lock.release( );使用file.seek( )设置文件偏移地址,保证写入文件的准确性。

def downloadThread(self,start,end):
    req = urllib2.Request(self.url)
    req.headers['Range'] = 'bytes=%s-%s' % (start, end)
    f = urllib2.urlopen(req)
    offset = start
    buffer = 1024
    while 1:
      block = f.read(buffer)
      if not block:
        break
      with lock:
        self.file.seek(offset)
        self.file.write(block)
        offset = offset + len(block)

  def download(self):
    filename = self.getFilename()
    self.file = open(filename, 'wb')
    thread_list = []
    n = 1
    for ran in self.get_range():
      start, end = ran
      print 'starting:%d thread '% n
      n += 1
      thread = threading.Thread(target=self.downloadThread,args=(start,end))
      thread.start()
      thread_list.append(thread)

    for i in thread_list:
      i.join()
    print 'Download %s Success!'%(self.file)
    self.file.close()

运行结果:

Python实现多线程HTTP下载器示例

将(*.py)文件转化为(*.exe)可执行文件

当写好了一个工具,如何让那些没有安装Python的人使用这个工具呢?这就需要将.py文件转化为.exe文件。

这里用到Python的py2exe模块,初次使用,所以对其进行介绍:

py2exe是一个将Python脚本转换成windows上可独立执行的可执行文件(*.exe)的工具,这样,就可以不用装Python在windows上运行这个可执行程序。

接下来,在multiThreadDownload.py的同目录下,创建mysetup.py文件,编写:

from distutils.core import setup
import py2exe

setup(console=["multiThreadDownload.py"])

接着执行命令:Python mysetup.py py2exe

生成dist文件夹,multiTjhreadDownload.exe文件位于其中,点击运行即可:

Python实现多线程HTTP下载器示例

Python实现多线程HTTP下载器示例

demo下载地址:HttpFileDownload_3water.rar

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python使用正则搜索字符串或文件中的浮点数代码实例
Jul 11 Python
13个最常用的Python深度学习库介绍
Oct 28 Python
Python自定义简单图轴简单实例
Jan 08 Python
python破解zip加密文件的方法
May 31 Python
Pycharm导入Python包,模块的图文教程
Jun 13 Python
python实现给微信指定好友定时发送消息
Apr 29 Python
Python应用领域和就业形势分析总结
May 14 Python
Django-Model数据库操作(增删改查、连表结构)详解
Jul 17 Python
TensorFlow基于MNIST数据集实现车牌识别(初步演示版)
Aug 05 Python
Python控制台输出时刷新当前行内容而不是输出新行的实现
Feb 21 Python
Keras自定义IOU方式
Jun 10 Python
深入探讨opencv图像矫正算法实战
May 21 Python
Python  pip安装lxml出错的问题解决办法
Feb 10 #Python
使用Python脚本和ADB命令实现卸载App
Feb 10 #Python
Python中str is not callable问题详解及解决办法
Feb 10 #Python
python用Pygal如何生成漂亮的SVG图像详解
Feb 10 #Python
Ubuntu下创建虚拟独立的Python环境全过程
Feb 10 #Python
简单谈谈Python中的几种常见的数据类型
Feb 10 #Python
Python使用QQ邮箱发送Email的方法实例
Feb 09 #Python
You might like
将博客园(cnblogs.com)数据导入到wordpress的代码
2013/01/06 PHP
PHP、Java des加密解密实例
2015/04/27 PHP
Yii基于数组和对象的Model查询技巧实例详解
2015/12/28 PHP
PHP 开发者该知道的 5 个 Composer 小技巧
2016/02/03 PHP
详解PHP中的序列化、反序列化操作
2017/03/21 PHP
php curl上传、下载、https登陆实现代码
2017/07/23 PHP
php mysql数据库操作类(实例讲解)
2017/08/06 PHP
php curl优化下载微信头像的方法总结
2018/09/07 PHP
jQuery Ajax文件上传(php)
2009/06/16 Javascript
js解决select下拉选不中问题
2014/10/14 Javascript
jQuery中的on与bind绑定事件区别实例详解
2017/02/28 Javascript
jQuery滚动监听实现商城楼梯式导航效果
2017/03/06 Javascript
JS简单实现点击按钮或文字显示遮罩层的方法
2017/04/27 Javascript
详谈表单重复提交的三种情况及解决方法
2017/08/16 Javascript
详解Vue路由钩子及应用场景(小结)
2017/11/07 Javascript
JavaScript 隐性类型转换步骤浅析
2018/03/15 Javascript
vuex进阶知识点巩固
2018/05/20 Javascript
node.js连接mysql与基本用法示例
2019/01/05 Javascript
JS实现图片懒加载(lazyload)过程详解
2020/04/02 Javascript
python实现按长宽比缩放图片
2018/06/07 Python
使用pygame写一个古诗词填空通关游戏
2019/12/03 Python
Python处理mysql特殊字符的问题
2020/03/02 Python
使用Python爬虫爬取小红书完完整整的全过程
2021/01/19 Python
英国123鲜花网站:123 Flowers
2019/07/07 全球购物
世界上最受欢迎的花店:1-800-Flowers.com
2020/06/01 全球购物
销售人员职业生涯规划范文
2014/03/01 职场文书
师范学院毕业生求职信
2014/06/24 职场文书
三月法制宣传月活动总结
2014/07/03 职场文书
工作检讨书怎么写
2014/10/10 职场文书
高中班主任评语
2014/12/30 职场文书
销售工作决心书
2015/02/04 职场文书
全国爱牙日活动总结
2015/02/05 职场文书
2015最新民情日记范文
2015/06/26 职场文书
2015年文秘个人工作总结
2015/10/14 职场文书
Python实现照片卡通化
2021/12/06 Python
详解OpenCV曝光融合
2022/04/29 Python