1.需求: 实现文件的断点下载
2.实现:
#!/usr/bin/python
# encoding=utf-8
import requests, sys, os, re, time
class download:
def __init__(self, config={
}):
self.config = {
'block': int(config['block'] if 'block' in config else 1024),
}
self.total = 0
self.size = 0
self.filename = ''
def touch_file(self, filename):
with open(filename, 'w') as f:
pass
def remove_nonchars(self, name):
(name, _) = re.subn(r'[\\\/\:\*\?\"\<\>\|]', '', name)
return name
def support_continue(self, url):
headers = {
'Range': 'bytes=0-4'}
try:
res = requests.head(url, headers=headers)
crange = res.headers['content-range']
self.total = int(re.match(r'^bytes 0-4/(\d+)$', crange).group(1))
return True
except:
pass
try:
self.total = int(res.headers['content-length'])
except:
self.total = 0
return False
def download(self, url, filename, headers={
}):
finished = False
block = self.config['block']
local_filename = self.remove_nonchars(filename) # 移除文件名称中的特殊字符
tmp_filename = local_filename + '.tmp'
size = self.size
if self.support_continue(url): # 支持断点续传
try:
with open(tmp_filename, 'rb') as f:
self.size = int(f.read())
size = self.size + 1
except:
self.touch_file(tmp_filename)
finally:
headers['Range'] = "bytes=%d-" % self.size
sys.stdout.write('\nlast download size: %s!\nthe start index for this time is: %s\n' % (self.size, size))
sys.stdout.flush()
else:
self.touch_file(tmp_filename)
self.touch_file(local_filename)
try:
res = requests.get(url, stream=True, verify=False, headers=headers)
except Exception as e:
sys.stdout.write('\ndownload failed: %s!\n' % (str(e)))
sys.stdout.flush()
os.remove(tmp_filename)
os.remove(local_filename)
return
start_t = time.time()
with open(local_filename, 'ab+') as f:
f.seek(self.size)
f.truncate()
try:
for chunk in res.iter_content(chunk_size=block):
if chunk:
f.write(chunk)
size += len(chunk)
f.flush()
sys.stdout.write('\b' * 64 + 'Now: %d, Total: %s' % (size, self.total))
sys.stdout.flush()
finished = True
os.remove(tmp_filename)
spend = int(time.time() - start_t)
speed = int((size - self.size) / 1024 / spend)
sys.stdout.write('\nDownload Finished!\nTotal Time: %ss, Download Speed: %sk/s\n' % (spend, speed))
sys.stdout.flush()
except Exception as e:
sys.stdout.write("\nDownload pause, reason: %s\n", str(e))
sys.stdout.flush()
finally:
if not finished:
with open(tmp_filename, 'wb') as tmp:
tmp.write(bytes(str(size), encoding="utf-8"))
if __name__ == '__main__':
url = "https://yos.yingzi.com/prod-bucket-iot/prod-iot-storage/979743213606400000/BH220_RK_123025080.diff"
filename = url.split('/')[-1]
download().download(url, filename)