#转载# python包requests下载大文件
requests单线程下载大文件
当使用requests的get下载大文件/数据时,建议使用使用stream模式。
当把get函数的stream参数设置成False时,它会立即开始下载文件并放到内存中,如果文件过大,有可能导致内存不足。
当把get函数的stream参数设置成True时,它不会立即开始下载,当你使用iter_content或iter_lines遍历内容或访问内容属性时才开始下载。需要注意一点:文件没有下载之前,它也需要保持连接。
- iter_content:一块一块的遍历要下载的内容
- iter_lines:一行一行的遍历要下载的内容
使用上面两个函数下载大文件可以防止占用过多的内存,因为每次只下载小部分数据。
示例代码:
1 2 3 4 5 |
r = requests.get(url_file, stream=True) f = open("file_path", "wb") for chunk in r.iter_content(chunk_size=512): if chunk: f.write(chunk) |
requests多线程下载(扩展)
- 把要下载的文件平均分成几块
- 每个线程分别下载对应的块
- 把各块写入到文件中相应的位置
示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# 在python3下测试 import sys import requests import threading import datetime # 传入的命令行参数,要下载文件的url url = sys.argv[1] def Handler(start, end, url, filename): headers = {'Range': 'bytes=%d-%d' % (start, end)} r = requests.get(url, headers=headers, stream=True) # 写入文件对应位置 with open(filename, "r+b") as fp: fp.seek(start) var = fp.tell() fp.write(r.content) def download_file(url, num_thread = 5): r = requests.head(url) try: file_name = url.split('/')[-1] file_size = int(r.headers['content-length']) # Content-Length获得文件主体的大小,当http服务器使用Connection:keep-alive时,不支持Content-Length except: print("检查URL,或不支持对线程下载") return # 创建一个和要下载文件一样大小的文件 fp = open(file_name, "wb") fp.truncate(file_size) fp.close() # 启动多线程写文件 part = file_size // num_thread # 如果不能整除,最后一块应该多几个字节 for i in range(num_thread): start = part * i if i == num_thread - 1: # 最后一块 end = file_size else: end = start + part t = threading.Thread(target=Handler, kwargs={'start': start, 'end': end, 'url': url, 'filename': file_name}) t.setDaemon(True) t.start() # 等待所有线程下载完成 main_thread = threading.current_thread() for t in threading.enumerate(): if t is main_thread: continue t.join() print('%s 下载完成' % file_name) if __name__ == '__main__': start = datetime.datetime.now().replace(microsecond=0) download_file(url) end = datetime.datetime.now().replace(microsecond=0) print("用时: ", end='') print(end-start) |
转载地址:http://blog.topspeedsnail.com/archives/8462