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里隐藏的“禅”
Jun 16 Python
Python使用django获取用户IP地址的方法
May 11 Python
Python IDLE入门简介
Dec 08 Python
python微信跳一跳游戏辅助代码解析
Jan 29 Python
Python爬取视频(其实是一篇福利)过程解析
Aug 01 Python
python日志模块logbook使用方法
Sep 19 Python
python3实现用turtle模块画一棵随机樱花树
Nov 21 Python
Python多个装饰器的调用顺序实例解析
May 22 Python
Python decimal模块使用方法详解
Jun 08 Python
PyQt5中QSpinBox计数器的实现
Jan 18 Python
解决pytorch读取自制数据集出现过的问题
May 31 Python
Python实现将多张图片合成MP4视频并加入背景音乐
Apr 28 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日历程序
2006/12/06 PHP
PHP版 汉字转码的实现详解
2013/06/09 PHP
php jq jquery getJSON跨域提交数据完整版
2013/09/13 PHP
详解WordPress开发中wp_title()函数的用法
2016/01/07 PHP
jquery在项目中做复选框时遇到的一些问题笔记
2013/11/17 Javascript
关于javaScript注册click事件传递参数的不成功问题
2014/07/18 Javascript
js实现模拟银行卡账号输入显示效果
2015/11/18 Javascript
浅谈js里面的InttoStr和StrtoInt
2016/06/14 Javascript
js 弹出对话框(遮罩)透明,可拖动的简单实例
2016/07/11 Javascript
基于jQuery实现滚动切换效果
2016/12/02 Javascript
socket io与vue-cli的结合使用的示例代码
2018/11/01 Javascript
jquery获取img的src值实例介绍
2019/01/16 jQuery
微信小程序中转义字符的处理方法
2019/03/28 Javascript
函数式编程入门实践(一)
2019/04/20 Javascript
微信小程序开发之获取用户手机号码(php接口解密)
2020/05/17 Javascript
编写v-for循环的技巧汇总
2020/12/01 Javascript
vue表单验证之禁止input输入框输入空格
2020/12/03 Vue.js
[51:53]完美世界DOTA2联赛决赛日 Inki vs LBZS 第二场 11.08
2020/11/10 DOTA
Python实现提取谷歌音乐搜索结果的方法
2015/07/10 Python
windows系统下Python环境搭建教程
2017/03/28 Python
Python 中Pickle库的使用详解
2018/02/24 Python
Python使用pymongo模块操作MongoDB的方法示例
2018/07/20 Python
tensorflow 加载部分变量的实例讲解
2018/07/27 Python
Matplotlib中文乱码的3种解决方案
2018/11/15 Python
python conda操作方法
2019/09/11 Python
python 实现多维数组转向量
2019/11/30 Python
Python如何读取、写入CSV数据
2020/07/28 Python
python+selenium自动化实战携带cookies模拟登陆微博
2021/01/19 Python
党的群众路线教育实践活动宣传方案
2014/02/23 职场文书
公司董事长助理工作职责
2014/07/12 职场文书
装饰施工员岗位职责
2015/04/11 职场文书
2015年新农村建设指导员工作总结
2015/07/24 职场文书
财务人员廉洁自律心得体会
2016/01/13 职场文书
高二英语教学反思
2016/03/03 职场文书
为什么node.js不适合大型项目
2021/04/28 Javascript
PostgreSQL13基于流复制搭建后备服务器的方法
2022/01/18 PostgreSQL