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) { ...
随机推荐
- Spring Cloud Alibaba微服务一站式解决方案-开篇v2.2.1.RELEASE
学习路线 **本人博客网站 **IT小神 www.itxiaoshen.com 生态概述 架构演进 什么是微服务 https://martinfowler.com/microservices/ Mic ...
- Codeforces Round #732 (Div.1) 题解
实在是打击人信心的一场比赛啊--一不注意就掉了 50+ 分,rating 没了啊/ll/dk/wq/kk A Weak pretest!!!!!11 /fn/fn/fn 一个很显然的注意点是在交换前后 ...
- CUDA计算矩阵相乘
1.最简单的 kernel 函数 __global__ void MatrixMulKernel( float* Md, float* Nd, float* Pd, int Width) { int ...
- AnnotationHub, clusterProfiler 进行GO,KEGG注释
️ AnnotationHub 目前最新的工具包叫做AnnotationHub,顾名思义,就是注释信息的中装站.通过它,能找到了几乎所有的注释资源.如果没有,你还可以根据已有的数据用它提供的函数进行构 ...
- ggplot2 图例及分页参数
图例: 1 theme(legend.title =element_blank()) 2 guides(fill = guide_legend(title = NULL)) # 去掉图例title 3 ...
- 同一局域网,远程连接别人的Mysql数据库
数据库:MySQL 工具: Navicat, 电脑A连接电脑B的数据库, 确保两部电脑都是在同一个局域网,都是连着同一个路由器,或者连接同一个WiFi, 如果不确定是否为同一个局域网,可以打开cmd, ...
- 学习Vue源码前的几项必要储备(一)
从接下来的一段时间里,Mg要进行阅读源码的工作.再阅读源码前,梳理一下准备工作. 7项重要储备 Flow 基本语法 发布/订阅模式 ES6+ 语法 原型链.闭包 函数柯里化 event loop 1. ...
- Linux定时任务crontable简介
Linux下定时执行任务的方法:Linux之crond 服务介绍:https://www.cnblogs.com/liang-io/p/9596294.html http://www.mamicode ...
- Linux启动初始化配置文件
Linux启动初始化配置文件(1)/etc/profile 登录时,会执行. 全局(公有)配置,不管是哪个用户,登录时都会读取该文件. (2)/ect/bashrc Ubuntu没有此文件,与之对应的 ...
- 高效读取大文件,再也不用担心 OOM 了!
内存读取 第一个版本,采用内存读取的方式,所有的数据首先读读取到内存中,程序代码如下: Stopwatch stopwatch = Stopwatch.createStarted(); // 将全部行 ...