
这几天琢磨着用python写个视频下载程序,但是单线程太慢,于是想采用多线程分段下载,中间踩了不少坑,在这里做个笔记。
import timeimport requestsimport threading
代码如下:
def getranges(url,num): r = requests.get(url) offset = int(int(r.headers['content-length'])/num) ranges = [] for i in range(num): if i == num - 1: ran = (i*offset,int(r.headers['content-length'])) else: ran = (i*offset,(i+1)*offset) ranges.append(ran) return ranges
我们先通过传入的url发起请求,获取相应头中的content-length字段,然后,根据传入的数字算出偏移量,也就是每个片段需要下多少个字节。
接下来就根据偏移量算出每一个文件片段的开始和结束的字节数,并保存到数组里待用。
代码如下
def download(url,start,end): headers = {'Range':'bytes=%s-%s'%(start,end)} r = requests.get(url,headers=headers,stream=True) contents.append((start,r.content)) # f.seek(start) # f.write(r.content) print(start,'/',end)
这里有个知识点,就是分段下载时一定要在请求头中用Range字段给出范围,注意书写格式
headers = {'Range':'bytes=%s-%s'%(start,end)}
这里我并没有将视频直接写入文件,而是放进了数组,因为多线程时执行的顺序会乱,无法保证从前到后依次写进文件,故先保存到数组,等后面再进行比对和写入,这里特意把文件开始的字节数也保存到了数组,以便比对。
代码如下
url = 'https://vt.media.tumblr.com/tumblr_ombi6xdbsN1v9z2zr.mp4#_=_'# try:f = open(str(int(time.time()))+'.mp4','wb')threads = []contents = []for ran in getranges(url,100): start,end = ran # download(url,f,start,end) t = threading.Thread(target=download,args=(url,start,end)) threads.append(t) t.start() for t in threads: t.join()for ran in getranges(url,100): start,end = ran for content in contents: start1,content1 = content if start == start1: f.seek(start) f.write(content1) f.close()
开启多线程进行 下载
将数组里的内容进行比对,依次写入文件,这里用seek方法写入,不懂的,大家自行百度一下
