urllib结合 concurrent.futures 多线程下载文件。
示例:
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
# @Time: 2020/12/16 10:42
# @Author:zhangmingda
# @File: urllib_multi_download.py
# @Software: PyCharm
# Description: 使用urllib 模块 实现多线程下载某个文件测试 from concurrent.futures import ThreadPoolExecutor, as_completed
from urllib.request import urlopen
from urllib.request import Request
from urllib.request import quote
import json
import math
import os class DownLoader(object):
def __init__(self):
self.part_size = 1024 * 1024 * 10 # 分块下载大小
self.part_thread_num = 10
self.BUFFER_SIZE = 64 * 1024 def download_part(self, encode_url, part_filename, offset, end_bytes):
"""
:param encode_url:经过URL编码的网络地址
:param part_filename: 文件块儿名字
:param offset: 下载字节起始点(包含)
:param end_bytes: 下载字节结束点(包含)
:return: (下载结果)
"""
# 构造请求头
range_header = {
'Range': 'bytes=%s-%s' % (offset, end_bytes)
}
print(range_header)
cur_task_ret = False
expected_file_size = end_bytes - offset + 1
part_req = Request(encode_url,headers=range_header)
with open(part_filename, 'wb') as local_part_fd:
with urlopen(part_req) as req_fd:
while True:
# 一直从网络读数据
data = req_fd.read(self.BUFFER_SIZE)
if not data:
break
local_part_fd.write(data)
if expected_file_size == os.stat(part_filename).st_size:
print('%s 与预期块儿文件大小相符' % part_filename)
cur_task_ret = True
# break
else:
print('%s 与预期块儿文件大小 不符,预期%s字节,实际得到%s 字节' % (
part_filename, expected_file_size, os.stat(part_filename).st_size)) return {part_filename: cur_task_ret} def download(self, url):
finally_filename = os.path.basename(url)
# 将URL编码成%字符串格式
encode_url = quote(url, safe=";/?:@&=+$,")
print(encode_url)
# 构造请求
req = Request(encode_url)
# 发起请求并且获取内容长度
with urlopen(req) as fp:
# print(json.dumps(dir(fp),indent=1))
print(fp.getheaders())
# length = fp.getheader('content-Range')
length = fp.getheader('Content-Length')
length = int(length)
print(type(length))
print('length:', length) # 分块任务列表
thread_list = []
# 每个块儿下载的结果
multi_chunk_download_result = {}
chunk_size = self.part_size
# 计算需要下载的块儿个数
chunk_count = int(math.ceil(length / float(chunk_size)))
pool_args_list = [] # 计算每个块儿请求的字节范围
for i in range(chunk_count):
offset = chunk_size * i
end_bytes = min(chunk_size * (i + 1), length) - 1
# 将一个文件划分的所有块儿任务,添加到任务列表
part_num = i + 1
part_filename = finally_filename + '.' + str(part_num)
# 每个块儿请求的范围,块儿名字,加到线程参数列表
pool_args_list.append((encode_url, part_filename, offset, end_bytes)) # ********开始多线程下载数据,并获取下载结果**************
# 构建线程池实例
tp = ThreadPoolExecutor(max_workers=self.part_thread_num)
# 全部添加到任务队列开始处理
[thread_list.append(tp.submit(self.download_part, *args)) for args in pool_args_list]
# 等待所有线程结束,获取全部线程的执行结果
[multi_chunk_download_result.update(part_thread.result()) for part_thread in as_completed(thread_list)] # 下载总结
print('下载总结')
# 如果任务数和块儿数对不上,报一下出入
if len(multi_chunk_download_result) != chunk_count:
raise RuntimeError(
"%s part miss,expect=%d,actual=%d" % (finally_filename, chunk_count, len(multi_chunk_download_result)))
# 如果任务都完毕,检查是否有失败的块儿
for item in multi_chunk_download_result.keys():
if not multi_chunk_download_result[item]:
raise RuntimeError("%s part upload has fail" % item)
# 都OK 整合文件
with open(finally_filename, 'wb') as local_fd:
for i in range(chunk_count):
part_filename = finally_filename + '.' + str(i + 1)
with open(part_filename, 'rb') as part_fd:
while True:
bytes_data = part_fd.read(self.BUFFER_SIZE)
if not bytes_data:
break
local_fd.write(bytes_data) if length == os.stat(finally_filename).st_size:
print('%s 下载完成,文件大小相符' % finally_filename)
for part_filename in multi_chunk_download_result.keys():
os.remove(part_filename)
else:
print('%s 下载完成,但大小不符,content_length:%s 下载后大小 %s' % (finally_filename, length,os.stat(finally_filename).st_size )) if __name__ == '__main__':
downloader = DownLoader()
url = 'https://ks3-cn-beijing.ksyun.com/zhangmingda/111-3333333.Python安装与命令行操作.mp4'
print(url)
downloader.download(url)
urllib结合 concurrent.futures 多线程下载文件。的更多相关文章
- 多线程下载文件,ftp文件服务器
1: 多线程下载文件 package com.li.multiplyThread; import org.apache.commons.lang3.exception.ExceptionUtils; ...
- java 网络编程基础 InetAddress类;URLDecoder和URLEncoder;URL和URLConnection;多线程下载文件示例
什么是IPV4,什么是IPV6: IPv4使用32个二进制位在网络上创建单个唯一地址.IPv4地址由四个数字表示,用点分隔.每个数字都是十进制(以10为基底)表示的八位二进制(以2为基底)数字,例如: ...
- Python之FTP多线程下载文件之分块多线程文件合并
Python之FTP多线程下载文件之分块多线程文件合并 欢迎大家阅读Python之FTP多线程下载系列之二:Python之FTP多线程下载文件之分块多线程文件合并,本系列的第一篇:Python之FTP ...
- Python之FTP多线程下载文件之多线程分块下载文件
Python之FTP多线程下载文件之多线程分块下载文件 Python中的ftplib模块用于对FTP的相关操作,常见的如下载,上传等.使用python从FTP下载较大的文件时,往往比较耗时,如何提高从 ...
- 教你如何在 Android 使用多线程下载文件
# 教你如何在 Android 使用多线程下载文件 前言 在 Android 日常开发中,我们会经常遇到下载文件需求,这里我们也可以用系统自带的 api DownloadManager 来解决这个问题 ...
- java 多线程下载文件 以及URLConnection和HttpURLConnection的区别
使用 HttpURLConnection 实现多线程下载文件 注意GET大写//http public class MultiThreadDownload { public static void m ...
- java 多线程下载文件并实时计算下载百分比(断点续传)
多线程下载文件 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来 ...
- AccessRandomFile多线程下载文件
写一个工具类 package com.pb.thread.demo; import java.io.File; import java.io.FileNotFoundException; import ...
- WPF多线程下载文件,有进度条
//打开对话框选择文件 private void OpenDialogBox_Click(object sender, RoutedEventArgs e) { ...
随机推荐
- .net core 和 WPF 开发升讯威在线客服系统:使用本地IP数据库实现访客来源快速定位,支持国外
本系列文章详细介绍使用 .net core 和 WPF 开发 升讯威在线客服与营销系统 的过程.本产品已经成熟稳定并投入商用. 免费使用 & 私有化部署:https://kf.shengxun ...
- 论文翻译:2020_A Recursive Network with Dynamic Attention for Monaural Speech Enhancement
论文地址:基于动态注意的递归网络单耳语音增强 论文代码:https://github.com/Andong-Li-speech/DARCN 引用格式:Li, A., Zheng, C., Fan, C ...
- JSOI(联合省选)2021 划水记
流水账. Day 0 18:10 去本部拿准考证,结果发现已经没有人了./ruo 敲了几份板子,很早就去睡觉了. Day 1 7:30 到 NFLS 拿到准考证,几乎没有人来.于是做起了政治作业. 然 ...
- Git常用操作(二)
仓库拉取 git clone XXX 修改仓库链接 $ git config -l # 显示coding列表 $ git config --get remote.origin.url # 返回orig ...
- python-django-自定义查询Q函数和F函数
数据库: def page_q(request): """Q函数的使用""" #查询username和nickname都是zhangsan ...
- dlang 读取gz压缩文件
没找到打开gz压缩文件的标准库,暂时调用系统命令打开gz压缩文件(参考:https://dlang.org/phobos/std_process.html#.Redirect.stdoutToStde ...
- Qemu/kvm虚拟化源码解析学习视频资料
地址链接:tao宝搜索:Linux云计算KVM Qemu虚拟化视频源码讲解+实践https://item.taobao.com/item.htm?ft=t&id=646300730262 L ...
- YARP+AgileConfig 5分钟实现一个支持配置热更新的代理网关
YARP 是微软开源的一个反向代理项目,英文名叫 Yet Another Reverse Proxy .所谓反向代理最有名的那就是 nginx 了,没错 YARP 也可以用来完成 nginx 的大部分 ...
- Mapreduce中的join操作
一.背景 MapReduce提供了表连接操作其中包括Map端join.Reduce端join还有半连接,现在我们要讨论的是Map端join,Map端join是指数据到达map处理函数之前进行合并的,效 ...
- Oracle带输入输出参数的存储过程
(一)使用输入参数 需求:在emp_copy中添加一条记录,empno为已有empno的最大值+1,ename不能为空且长度必须大于0,deptno为60. 创建存储过程: create or rep ...