#-*- coding=utf-8 -*-
importsysimportosimportos.pathimporttimeimporturllib.request, urllib.parse, urllib.errorfrom threading importThread
local_proxies={}classThreadDownComplete:def __init__(self, down_loaded):
self.down_loaded=down_loadedclassThreadDown(Thread, urllib.request.FancyURLopener):def __init__(self, thread_name, url, filename, ranges=0, proxies={}):
Thread.__init__(self, name=thread_name)
urllib.request.FancyURLopener.__init__(self, proxies)
self.name=thread_name
self.url=url
self.filename=filename
self.ranges=ranges
self.down_loaded=0
self.url_handler=None
self.one_time_size= 16384 #16kByte/time
self.data_start_point =self.ranges[0]
self.data_end_point= self.ranges[1]
self.down_start_time=int(time.time())
self.recent_down_time=int(time.time())
self.stop=False
self.complete=False
self.download_loan= self.data_end_point -self.data_start_pointtry:
self.down_loaded=os.path.getsize(self.filename)exceptOSError:
self.down_loaded=0
self.start_point= self.data_start_point +self.down_loadedif notself.complete_check():
self.data_check()defstart_reset(self):try:
os.remove(self.filename)except:passself.down_loaded=0
self.complete=False
self.stop=False
self.start_point=self.data_start_pointdefdata_check(self):if self.start_point >self.data_end_point:print("Part %s has been down_loaded over.\n" %self.filename)
self.start_reset()defflow_check(self):if self.down_loaded > self.download_loan + 1:
self.stop=FalsereturnFalsereturnTruedefcomplete_check(self):if self.down_loaded == self.download_loan + 1:
self.complete=True
self.stop=TruereturnTruereturnFalsedefdown(self):try:returnself.url_handler.read(self.one_time_size)except:return ''
def __run(self):print("task %s will down_load from %d to %d" %(self.name, self.start_point, self.data_end_point))
self.addheader("Range", "bytes=%d-%d" %(self.start_point, self.data_end_point))
self.url_handler=self.open(self.url)
data=self.down()while not self.stop and notself.complete:ifdata:
self.recent_down_time=int(time.time())
file_handler= open(self.filename, 'ab+')
file_handler.write(data)
file_handler.close()
self.down_loaded+=len(data)ifself.complete_check():break
if notself.flow_check():breakdata=self.down()defrun(self):ifself.complete:returnself.__run()
self.complete_check()while not self.stop and notself.complete:
self.start_reset()
self.__run()
self.complete_check()def get_file_size(url, proxies={}):
url_handler=urllib.request.urlopen(url)return int(url_handler.info()['Content-Length'])defsplit_blocks(total_size, block_number):
block_size= int(total_size /block_number)
ranges=[]for i in range(0, block_number - 1):
ranges.append((i* block_size, (i + 1) * block_size - 1))
ranges.append(((block_number- 1) * block_size, total_size - 1))returnrangesdefis_live(tasks):for index, task inenumerate(tasks):ifisinstance(task, ThreadDownComplete):continue
if int(time.time()) - task.recent_down_time > 8:
thread_name=task.name
filename=task.filename
ranges=task.ranges
url=task.url
task.stop=True
tasks[index]=start_down_thread(thread_name, url, filename, ranges)returnTrueiftask.complete:
tasks[index]=ThreadDownComplete(task.down_loaded)iftask.is_alive():returnTruereturnFalsedefstart_down_thread(thread_name, url, filename, ranges):
task=ThreadDown(thread_name, url, filename, ranges)
task.setDaemon(True)
task.start()returntaskdeflog(msg):
sys.stdout.write(msg)
sys.stdout.flush()def down_load(url, output, blocks=6, proxies=local_proxies):
down_file_size=get_file_size(url, proxies)
ranges=split_blocks(down_file_size, blocks)
thread_name= ["thread_%d" % i for i inrange(0, blocks)]
filename= [output + "_%d" % i for i inrange(0, blocks)]
tasks=[]for i inrange(0, blocks):
tasks.append(start_down_thread(thread_name[i], url, filename[i], ranges[i]))whileis_live(tasks):
down_loaded= sum([task.down_loaded for task intasks])
process= down_loaded / float(down_file_size) * 100log("\rfilesize:%d down_loaded:%d Completed:%.2f%%" %(down_file_size, down_loaded, process))
time.sleep(0.01)
file_handler= open(output, 'wb+')for i infilename:
f= open(i, 'rb')
file_handler.write(f.read())
f.close()try:
os.remove(i)pass
except:passfile_handler.close()if os.path.getsize(output) ==down_file_size:
log("\nCompleted\n")else:
log("\nError\n")
sys.exit(0)if __name__ == '__main__':
_url= "http://dldir1.qq.com/qqfile/qq/QQ7.9Light/14308/QQ7.9Light.exe"down_load(_url, os.path.basename(_url), blocks=30, proxies={})