设为首页 加入收藏

TOP

Python3 多线程下载代码(一)
2015-12-15 23:09:06 来源: 作者: 【 】 浏览:2
Tags:Python3 线程 下载 代码

Python3 多线程下载代码,貌似原版源自Axel这个多线程下载工具。


'''
Created on 2014-10-24


@author: Maple
'''


import sys
import os
import time
import getopt
import urllib.request
import urllib.parse
from threading import Thread


#===============================================================================
# def download(url, output=os.getcwd(), blocks=6, proxies=local_proxies)
# output:输出文件路径,默认为当前路径
# blocks:线程数
# proxies:代理地址
#===============================================================================


local_proxies = {}#代理地址


class Maple(Thread):
? ? version = "Mozilla/5.0"


? ? def __init__(self, threadname, url, filename, ranges=0, proxies={}):
? ? ? ? Thread.__init__(self, name=threadname)
? ? ? ? self.name = threadname
? ? ? ? self.url = url
? ? ? ? self.proxies = proxies
? ? ? ? self.filename = filename
? ? ? ? self.ranges = ranges
? ? ? ? self.downloaded = 0


? ? def run(self):


? ? ? ? try:
? ? ? ? ? ? self.downloaded = os.path.getsize( self.filename )? ? ? ? #获取已下载的文件字节块块,支持断点续传
? ? ? ? except OSError:
? ? ? ? ? ? #print 'never downloaded'
? ? ? ? ? ? self.downloaded = 0
? ? ? ? opener=GetUrlOpener(self.proxies)? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #根据代理参数生成相应的url opener
? ? ? ? if self.ranges:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #ranges为线程需要下载的文件块的字节范围
? ? ? ? ? ? # rebuild start poind
? ? ? ? ? ? self.startpoint = self.ranges[0] + self.downloaded? ? ? ? #从已下载字节块后的位置开始下载


? ? ? ? ? ? # This part is completed
? ? ? ? ? ? if self.startpoint >= self.ranges[1]:
? ? ? ? ? ? ? ? self.downloaded = self.ranges[1] - self.ranges[0]? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? ? ? ? ? print ('Part %s has been downloaded over.' % self.filename)
? ? ? ? ? ? ? ? return
? ? ? ? ? ? opener.addheaders=[('Range','bytes={}-{}'.format(self.startpoint, self.ranges[1])),('User-agent','Mozilla/5.0')]? ? #添加请求头部内容,仅下载指定范围的字节,伪装成浏览器请求
? ? ? ? ? ? print ('task %s will download from %d to %d' % (self.name, self.startpoint+1, self.ranges[1]+1))
? ? ? ? else:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #ranges未指定(文件大小未知,无法切割),从已下载字节块后的位置开始下载剩余全部字节
? ? ? ? ? ? self.startpoint = self.downloaded
? ? ? ? ? ? opener.addheaders=[('Range','bytes={}-'.format(self.startpoint)),('User-agent','Mozilla/5.0')]
? ? ? ? self.fetchsize = 16384? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #每次读取的字节数
? ? ? ? self.urlhandle = opener.open(self.url)? ? ? ? ? ? ? ? ? ? ? ? ? ? #打开文件地址
? ? ? ? data = self.urlhandle.read( self.fetchsize )? ? ? ? ? ? ? ? ? ? ?
? ? ? ? while data:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? #循环读取数据写入临时文件,并更新已下载字节数
? ? ? ? ? ? filehandle = open( self.filename, 'ab+' )
? ? ? ? ? ? filehandle.write( data )
? ? ? ? ? ? filehandle.close()
? ? ? ? ? ? self.downloaded += len( data )
? ? ? ? ? ? data = self.urlhandle.read( self.fetchsize )


def Sec2Time(second):? ? ? ? ? ? ? ? ? ? ? ? #将秒数转换为标准时间格式。以为有现成的函数,结果愣是没找到
? ? day=second//(3600*24)
? ? second-=day*3600*24
? ? hour=second//3600
? ? second -=hour*3600
? ? minute=second//60
? ? second-=minute*60
? ? if day == 0:
? ? ? ? if hour == 0:
? ? ? ? ? ? if minute == 0:
? ? ? ? ? ? ? ? return '{:0.2f}S.'.format(second)
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? return '{:02}M:{:0.2f}S'.format(minute,second)
? ? ? ? else:
? ? ? ? ? ? return '{:02}H:{:02}M:{:0.2f}S'.format(hour,minute,second)
? ? else:
? ? ? ? return '{:03}D:{:02}H:{:02}M:{:0.2f}S'.format(day,hour,minute,second)


def GetUrlOpener(proxies={}):? ? ? ? #分析代理参数,返回url opener。完整代理格式:user/passwd@http://127.0.0.1:8087。如格式不同,需要修改此分析函数
? ? if proxies:
? ? ? ? try:
? ? ? ? ? ? ap=proxies.split('@')
? ? ? ? ? ? if len(ap) > 1:
? ? ? ? ? ? ? ? auth=ap[0]
? ? ? ? ? ? ? ? addr=ap[1]
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? addr=ap[0]
? ? ? ? ? ? ? ? auth=''
? ? ? ? ? ? if '://' in addr:
? ? ? ? ? ? ? ? ptype=addr[:addr.find('://')]
? ? ? ? ? ? ? ? phost=addr[addr.find('://')+3:]
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? ptype='http'
? ? ? ? ? ? ? ? phost=addr
? ? ? ? ? ? proxy={ptype:ptype+'://'+phost}
? ? ? ? ? ? proxy_handler = urllib.request.ProxyHandler(proxy)
? ? ? ? except Exception as ex:
? ? ? ? ? ? print(ex)
? ? ? ? ? ? return urllib.request.build_opener()
? ? ? ? try:
? ? ? ? ? ? authlist=auth.split('/')
? ? ? ? ? ? if len(authlist) > 1:
? ? ? ? ? ? ? ? user=authlist[0]
? ? ? ? ? ? ? ? passwd=authlist[1]
? ? ? ? ? ? ? ? proxy_auth_handler = urllib.request.ProxyBasicAuthHandler()
? ? ? ? ? ? ? ? proxy_auth_handler.add_password('realm',phost,user,passwd)
? ? ? ? ? ? ? ? opener = urllib.request.build_opener(proxy_handler,proxy_auth_handler)
? ? ? ? ? ? else:
? ? ? ? ? ? ? ? opener = urllib.request.build_opener(proxy_handler)
? ? ? ? ? ? return opener
? ? ? ? except Exception as ex:
? ? ? ? ? ? print(ex)
? ? ? ? ? ? return urllib.request.build_opener(proxy_handler)
? ? else:
? ? ? # urlHandler=urllib.request.urlopen(url)
? ? ? ? return urllib.request.build_opener()


def GetUrlFileInfo(url,proxies={}):? ? ? ? ? ? #获取要下载的文件的信息,包括文件名,文件类型和文件大小
? ? scheme, netloc, path, query, fragment = urllib.parse.urlsplit(url)? ? #分析url
? ? filename=urllib.parse.unquote(path)? ? ? #如果url中的文件名部分存在中文,将其正确解码出来
? ? filename=filename.split('/')[-1]
? ? opener=GetUrlOpener(proxies)? ? ? ? ? #通过网络请求读取响应头部,根据头部获取文件信息。文件名以服务器返回的文件名信息为准
? ? urlHandler=opener.open(url)
? ? headers=urlHandler.info()
? ? if 'Content-Disposition' in headers:? ? ? #Content-Disposition字段有可能获取到文件名,不过可能是乱码,没找到解决办法
? ? ? ? disposition=headers.get('Content-Disposition')
? ? ? ? if 'filename=' in disposition:
? ? ? ? ? ? filename = disposition.split('filename=')[1]
? ? ? ? ? ? if filename[0] == '"' or filename[0] == "'":
? ? ? ? ? ? ? ? filename = filename[1:-1]
? ? filename=urllib.parse.unquote(filename)
? ? if filename:
? ? ? ? (name,ext)=os.path.splitext(filename)
? ? else:
? ? ? ?

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇C语言查看各种数据类型的size 下一篇Java JNI的使用基础

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: