使用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 ...
随机推荐
- spring boot整合mybatis+mybatis-plus
Spring boot对于我来说是一个刚接触的新东西,学习过程中,发现这东西还是很容易上手的,Spring boot没配置时会默认使用Spring data jpa,这东西可以说一个极简洁的工具,可是 ...
- python3 验证码去噪
处理前图像: 处理后图像 代码 #coding:utf8 import os from PIL import Image,ImageDraw,ImageFile import numpy import ...
- 【Spark】SparkStreaming-流处理-规则动态更新-解决方案
SparkStreaming-流处理-规则动态更新-解决方案 image2017-10-27_11-10-53.png (1067×738) elasticsearch-head Elasticsea ...
- AdMaster技术副总裁谈Hadoop、营销数据、Python和挖掘平台
http://www.infoq.com/cn/news/2014/09/admaster-hadoop 卢亿雷是现任AdMaster技术副总裁,曾在联想研究院.百度基础架构部.Carbonite C ...
- SciPy 安装不上?
参考:链接:https://www.zhihu.com/question/30188492/answer/150928275来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处 ...
- spring 读取配置文件,将值注入到静态字段
resources/config/config-dev.properties es.ip.node=xxxxxxxcluster.name=xxxxxxxclient.transport.sniff= ...
- 一次jdbc乱码解决
今天我做了一个小实验,从sqlserver 2010中将一张表转移到mysql中,使用的是基本的jdbc,前面复制的好好地,不知道怎么了,到了第三万行,突然出现了下面的异常 Incorrect str ...
- [Functional Programming] Arrow Functor with contramap
What is Arrow Functor? Arrow is a Profunctor that lifts a function of type a -> b and allows for ...
- Android LazyList 从网络获取图片并缓存
原演示地址 本文内容 环境 演示 LazyList 从网络获取图片并缓存 参考资料 本文是 Github 上的一个演示,通过网络获取歌手专辑的缩略图,并显示在 ListView 控件中.该演示具备将缩 ...
- mybatis学习资源
官网:http://mybatis.org/index.html 代码:https://code.google.com/p/mybatisnet/ wiki:http://zh.wikipedia.o ...