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对字典进行排序实例
Sep 25 Python
Python中的两个内置模块介绍
Apr 05 Python
在Python中处理字符串之isdecimal()方法的使用
May 20 Python
Python json模块dumps、loads操作示例
Sep 06 Python
Python使用pandas和xlsxwriter读写xlsx文件的方法示例
Apr 09 Python
详解Python 解压缩文件
Apr 09 Python
Python/Django后端使用PIL Image生成头像缩略图
Apr 30 Python
python线程信号量semaphore使用解析
Nov 30 Python
python 多维高斯分布数据生成方式
Dec 09 Python
python飞机大战 pygame游戏创建快速入门详解
Dec 17 Python
python PyAUtoGUI库实现自动化控制鼠标键盘
Sep 09 Python
VSCode中autopep8无法运行问题解决方案(提示Error: Command failed,usage)
Mar 02 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
php的list()的一步操作给一组变量进行赋值的使用
2011/05/18 PHP
php查询whois信息的方法
2015/06/08 PHP
Yii框架上传图片用法总结
2016/03/28 PHP
注释PHP和html混合代码的小技巧(分享)
2016/11/03 PHP
自己的js工具 Event封装
2009/08/21 Javascript
Javascript对象中关于setTimeout和setInterval的this介绍
2012/07/21 Javascript
jquery动画2.元素坐标动画效果(创建一个图片走廊)
2012/08/24 Javascript
Ajax提交与传统表单提交的区别说明
2014/02/07 Javascript
点击A元素触发B元素的事件在IE8下会识别成A元素
2014/09/04 Javascript
JavaScript中的null和undefined区别介绍
2015/01/01 Javascript
使用jQuery在对象中缓存选择器的简单方法
2015/06/30 Javascript
需要牢记的JavaScript基础知识
2016/09/25 Javascript
微信小程序 Image API实例详解
2016/09/30 Javascript
详解vue中点击空白处隐藏div的实现(用指令实现)
2018/04/19 Javascript
json前后端数据交互相关代码
2018/09/19 Javascript
vue.js实现备忘录demo
2019/06/26 Javascript
JS实现联想、自动补齐国家或地区名称的功能
2020/07/07 Javascript
[01:21]2018DOTA2亚洲邀请赛4.5采访 打DOTA2也能有女朋友?
2018/04/06 DOTA
python通过yield实现数组全排列的方法
2015/03/18 Python
Python实现八皇后问题示例代码
2018/12/09 Python
python读取几个G的csv文件方法
2019/01/07 Python
python语言元素知识点详解
2019/05/15 Python
python 判断文件还是文件夹的简单实例
2019/06/10 Python
解决Django加载静态资源失败的问题
2019/07/28 Python
python构造IP报文实例
2020/05/05 Python
python利用opencv保存、播放视频
2020/11/02 Python
使用CSS3实现多列布局与多背景的技巧
2016/02/29 HTML / CSS
数组越界问题
2015/10/21 面试题
卫校中专生的自我评价
2014/01/15 职场文书
大学生创业感言
2014/01/25 职场文书
大学军训心得体会800字
2016/01/11 职场文书
2019年幼儿园管理条例范本!
2019/07/17 职场文书
idea 在springboot中使用lombok插件的方法
2021/08/02 Java/Android
python模块与C和C++动态库相互调用实现过程示例
2021/11/02 Python
实战Python爬虫爬取酷我音乐
2022/04/11 Python
vue如何在data中引入图片的正确路径
2022/06/05 Vue.js