使用requests库实现多线程下载
多线程下载主要用到http请求中的header
- Content-Length:资源长度,用于确认资源的总长度,从而便于规划每个线程的任务量
- Range:bytes=beg1-end1;beg2-end2,用来控制下载的资源的某一部分,需要注意,这里的beg、end是前闭后闭区间。
当下载的片段较小时,很容易出错,需要重试,可以使用retry模块通过注解方式实现重试,这个模块非常好用。
Python的多线程没有体现出优势来。链条的强度取决于最薄弱的一环,木桶的容量取决于最短的木板,系统的的并发量取决于并发量最小的模块。多线程体现不出优势,可能是因为网速。如果单线程就能够将网速充分利用起来,那么多线程就没有用了。
import os
import threading
import time
import requests
import retry
url = 'http://mp4.vjshi.com/2017-12-18/422ded2944a95d6ca09752e04f687dd6.mp4'
def one_thread():
# 37.86秒
begTime = time.time()
resp = requests.get(url)
with open("haha.mp4", "wb") as f:
f.write(resp.content)
endTime = time.time()
print(endTime - begTime)
def multi_thread():
PER_THREAD_MIN = 2000 # 每个线程至少下载量
MAX_THREAD_COUNT = 50 # 最多线程数
TEMP_FOLDER = "dow" # 临时文件夹
TARGET_FILE_NAME = "mul.mp4" # 存储目标
if not os.path.exists(TEMP_FOLDER):
os.mkdir(TEMP_FOLDER)
begTime = time.time()
resp = requests.get(url, stream=True)
sz = int(resp.headers['Content-Length'])
block_sz = max(sz // MAX_THREAD_COUNT, PER_THREAD_MIN)
task = []
cnt = 0
for i in range(0, sz, block_sz):
now_sz = sz - i if sz - i - block_sz < PER_THREAD_MIN else block_sz
it = {
'beg': i,
'end': i + now_sz,
'path': os.path.join(TEMP_FOLDER, str(cnt)),
'last': i + now_sz == sz
}
task.append(it)
cnt += 1
if it['last']:
break
lock = threading.Lock()
def merge():
with open(TARGET_FILE_NAME, "wb") as f:
for j, i in enumerate(task):
with open(i['path'], 'rb') as ff:
f.write(ff.read(i['end'] - i['beg']))
endTime = time.time()
print(endTime - begTime)
@retry.retry(tries=100)
def go(it):
nonlocal cnt
print(it)
resp = requests.get(url, headers={
'Range': "bytes=%d-%d" % (it['beg'], it['end'] - 1)
})
if resp.status_code not in [200, 206]:
print(it, resp.status_code, '爬虫失败')
raise Exception("爬虫失败")
if len(resp.content) != it['end'] - it['beg']:
print("长度不对")
raise Exception("长度不对")
with open(it['path'], 'wb') as f:
f.write(resp.content)
print(it, it['end'] - it['beg'], len(resp.content), 'over', resp.status_code)
lock.acquire(timeout=0)
cnt -= 1
if cnt == 0:
merge()
lock.release()
def start_threading():
for i in task:
threading.Thread(target=go, args=(i,)).start()
start_threading()
# one_thread()
multi_thread()
使用requests库实现多线程下载的更多相关文章
- HTTP多线程下载+断点续传(libcurl库)
目录索引: 一.LibCurl基本编程框架 二.一些基本的函数 三.curl_easy_setopt函数部分选项介绍 四.curl_easy_perform 函数说明(error 状态码) 五.lib ...
- requests库下载图片的方法
方法: 传入图片url,requests.get()方法请求一下,将源码以二进制的形式写在本地即可. 以前一直以为requests库中有特定的方法获取图片,类似urllib.request.urlre ...
- python下载安装requests库
一.python下载安装requests库 1.到git下载源码zip源码https://github.com/requests/requests 2.解压到python目录下: 3.“win+R”进 ...
- requests库入门12-文件上传和下载
因为找不到可以演示上传接口,所以只能纯代码了 文件上传 上传文件是在请求中使用files参数,files需要指向一个dict,然后dict里面的键是接口中对应文件名的字段,而值就是打开这个文件读取到内 ...
- 从0开始学爬虫11之使用requests库下载图片
从0开始学爬虫11之使用requests库下载图片 # coding=utf-8 import requests def download_imgage(): ''' demo: 下载图片 ''' h ...
- 下载requests库
下载requests库 第一步:找到python的安装位置,可以从下面的图中找到 第二步:复制scripts文件夹的位置 第三步:win+r打开cmd cd 到scripts文件夹的位置 第四步:运行 ...
- Python爬虫之多线程下载豆瓣Top250电影图片
爬虫项目介绍 本次爬虫项目将爬取豆瓣Top250电影的图片,其网址为:https://movie.douban.com/top250, 具体页面如下图所示: 本次爬虫项目将分别不使用多线程和使 ...
- 【转载-译文】requests库连接池说明
转译自:https://laike9m.com/blog/requests-secret-pool_connections-and-pool_maxsize,89/ Requests' secret: ...
- python -使用Requests库完成Post表单操作
""" 使用Requests库完成Post表单操作 """ #_*_codingn:utf8 _*_ import requests fro ...
随机推荐
- @class指令的使用
@class指令能够减少编译时间,告诉编译器“相信我,你最终能了解这个名称的类”,可以减少不得不导入的头文件的数量. sample如下: #import <Foundation/Foundati ...
- ueditor插入自定义内容和样式
UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点 通过UEditor提供的API接口可以很方便的读写操作内容并设置编辑器里的样式 页 ...
- 【Nodejs】使用request批量下载MP3,文件数量内容都没问题
看来request远强于http.request是毋庸置疑的了. 代码如下: //====================================================== // 喜 ...
- Redis内存淘汰机制
转自:https://my.oschina.net/andylucc/blog/741965 摘要 Redis是一款优秀的.开源的内存数据库,我在阅读Redis源码实现的过程中,时时刻刻能感受到Red ...
- (算法)从0到n整数中数字2出现的次数
题目: 数出0到n(含)中数字2出现了几次. 思路: 1.暴力方法,数出每个数字包含几个2,然后累加起来. 2.分析:分别考虑数字n每一位出现2的次数,如123123: 从左往右考虑4123123: ...
- 3611: [Heoi2014]大project|树形DP|虚树
构建出虚树然后DP统计答案 自己写的DP太傻QAQ,各种WA 膜了一发PoPoQQQ大爷的DP方法 mxdis,mndis分别表示到当前点近期和最远的被选出来的点的距离 mx,mn分别表示在以当前点为 ...
- javascript数组操作大全,数组方法总汇
1. shift:删除原数组第一项,并返回删除元素的值:如果数组为空则返回undefined var a = [1,2,3,4,5]; var b = a.shift(); //a:[2,3,4,5] ...
- MVC 之 缓存机制(二)
八.应用程序缓存 应用程序缓存提供了一种编程方式,可通过键/值对将任意数据存储在内存中. 使用应用程序缓存与使用应用程序状态类似. 但是,与应用程序状态不同的是,应用程序缓存中的数据是易失的, 即数据 ...
- Android Studio 之 环境搭建
从网上整理的安装步骤及初次使用问题解决. 一.安装步骤 1.安装前确认JDK已经安装并配置好环境变量(要求JDK1.7以上的版本). 2.官网下载Windows安装包,网上下载的版本是android- ...
- 局域网内主机ssh访问服务器宿主下VMWare 虚拟机(Ubuntu 12.04.1)并且实现虚拟机能上网的那点事
(1)首先虚拟机已安装ssh服务 1) 自动安装 ssh 服务 apt-get install openssh-server 安装完成后,将自动开启 ssh 服务. 2) 查看 ssh 服务是否已开启 ...