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) { ...
随机推荐
- 【Cloud Computing】Hadoop环境安装、基本命令及MapReduce字数统计程序
[Cloud Computing]Hadoop环境安装.基本命令及MapReduce字数统计程序 1.虚拟机准备 1.1 模板机器配置 1.1.1 主机配置 IP地址:在学校校园网Wifi下连接下 V ...
- 【NOIP 2018】摆渡车
前情提要 是的 我终于回来补坑了 一年了哇 你这个鸽子王 斜率优化版本 今天在复习斜率优化的时候才想起来这个题 定义就不设了 大家想看可以看上面那个原版 怎么斜率优化呢? 我们考虑\(i\)点是当前的 ...
- [NOIP2017 提高组] 宝藏
考虑到这种对于某种操作顺序有一个权值. 且这个权值有一个\(O(n)\)或者更好的复杂度求出. 求最值. 那可以用模拟退火. #include<iostream> #include< ...
- 常见 js 数组方法使用详解
数组常用方法总结 concat filter map some every reduce sort includes join some every 语法:array.every(function(c ...
- [R]在dplyr函数的基础上编写函数-(3)tidyeval
dplyr的优点很明显,数据框操作简洁,如filter(df, x == 1, y == 2, z == 3)等于df[df$x == 1 & df$y ==2 & df$z == 3 ...
- Hive-insert into table 与 insert overwrite table 区别
区分insert into 和 insert overowrite: 0. 命令格式 INSERT OVERWRITE|INTO TABLE tablename [PARTITION (partcol ...
- nginx 的一个conf配置
server { listen 80 default_server; server_name www.caipudq.cn caipudq.cn *.caipudq.cn; root /mnt/www ...
- 基于Kubernetes实现前后端应用的金丝雀发布
基于Kubernetes实现前后端应用的金丝雀发布 公司的研发管理平台实现了Gitlab+Kubernetes的Devops,在ToB和ToC场景中,由于用户量大,且预发布环境和生产环境或多或少存在差 ...
- 大数据学习day17------第三阶段-----scala05------1.Akka RPC通信案例改造和部署在多台机器上 2. 柯里化方法 3. 隐式转换 4 scala的泛型
1.Akka RPC通信案例改造和部署在多台机器上 1.1 Akka RPC通信案例的改造(主要是把一些参数不写是) Master package com._51doit.akka.rpc impo ...
- 【XSS】再谈CSP内容安全策略
再谈CSP内容安全策略 之前每次都是想的很浅,或者只是个理论派,事实证明就是得动手实践 参考 CSP的用法 官方文档 通过设置属性来告诉浏览器允许加载的资源数据来源.可通过Response响应头来设置 ...