示例:

#!/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 多线程下载文件。的更多相关文章

  1. 多线程下载文件,ftp文件服务器

    1: 多线程下载文件 package com.li.multiplyThread; import org.apache.commons.lang3.exception.ExceptionUtils; ...

  2. java 网络编程基础 InetAddress类;URLDecoder和URLEncoder;URL和URLConnection;多线程下载文件示例

    什么是IPV4,什么是IPV6: IPv4使用32个二进制位在网络上创建单个唯一地址.IPv4地址由四个数字表示,用点分隔.每个数字都是十进制(以10为基底)表示的八位二进制(以2为基底)数字,例如: ...

  3. Python之FTP多线程下载文件之分块多线程文件合并

    Python之FTP多线程下载文件之分块多线程文件合并 欢迎大家阅读Python之FTP多线程下载系列之二:Python之FTP多线程下载文件之分块多线程文件合并,本系列的第一篇:Python之FTP ...

  4. Python之FTP多线程下载文件之多线程分块下载文件

    Python之FTP多线程下载文件之多线程分块下载文件 Python中的ftplib模块用于对FTP的相关操作,常见的如下载,上传等.使用python从FTP下载较大的文件时,往往比较耗时,如何提高从 ...

  5. 教你如何在 Android 使用多线程下载文件

    # 教你如何在 Android 使用多线程下载文件 前言 在 Android 日常开发中,我们会经常遇到下载文件需求,这里我们也可以用系统自带的 api DownloadManager 来解决这个问题 ...

  6. java 多线程下载文件 以及URLConnection和HttpURLConnection的区别

    使用 HttpURLConnection 实现多线程下载文件 注意GET大写//http public class MultiThreadDownload { public static void m ...

  7. java 多线程下载文件并实时计算下载百分比(断点续传)

    多线程下载文件 多线程同时下载文件即:在同一时间内通过多个线程对同一个请求地址发起多个请求,将需要下载的数据分割成多个部分,同时下载,每个线程只负责下载其中的一部分,最后将每一个线程下载的部分组装起来 ...

  8. AccessRandomFile多线程下载文件

    写一个工具类 package com.pb.thread.demo; import java.io.File; import java.io.FileNotFoundException; import ...

  9. WPF多线程下载文件,有进度条

    //打开对话框选择文件         private void OpenDialogBox_Click(object sender, RoutedEventArgs e)         {     ...

随机推荐

  1. 什么是H5

    H5其实就是HTML5 常说的H5测试,就是移动端web页面,他跟安卓app与IOS app的区别: (1)以往的app是使用的原生系统内核的,相当于直接在系统上操作,是传统意义上的软件,更加稳定 ( ...

  2. [Bzoj 1432] [ZJOI2009]Function(结论推导题)

    我们先看一下题目: (有没有和我一样的朋友看到这道题以为是几何不可做题 这个题目真的很难理解,并且样例也给得太水了吧! 理解题目是必不可少的(这并不是你看了半小时题目的理由)--首先我们先简化题目 1 ...

  3. 微前端框架 single-spa 技术分析

    在理解微前端技术原理中我们介绍了微前端的概念和核心技术原理.本篇我们结合目前业内主流的微前端实现 single-spa 来说明在生产实践中是如何实现微前端的. single-spa 的文档略显凌乱,概 ...

  4. Oracle JDK 下载、配置与验证

    # 1. 解决官网下载JDK需要登录Oracle账号问题(JDK 8) JDK 1.8 官网下载地址: https://www.oracle.com/java/technologies/javase/ ...

  5. Python异步IO之select

    1. select模块的基本使用(以socket为例) 1 # -*- coding:utf-8 -*- 2 # Author:Wong Du 3 4 import select 5 import s ...

  6. 表格table的宽度问题

    首先注意table的一个样式 table { table-layout:fixed; } table-layout有以下取值: automatic 默认.列宽度由单元格内容设定 fixed 列宽由表格 ...

  7. 100个Shell脚本——【脚本9】统计ip

    [脚本9]统计ip 有一个日志文件,日志片段:如下: 112.111.12.248 – [25/Sep/2013:16:08:31 +0800]formula-x.haotui.com "/ ...

  8. 解决ViewPager与ScrollView 冲突

    ViewPager来实现左右滑动切换tab,如果tab的某一项中嵌入了水平可滑动的View就会让你有些不爽,比如想滑动tab项中的可水平滑动的控件,却导致tab切换. 因为Android事件机制是从父 ...

  9. linux 6.5 网卡

    启动网卡 ifup eth0 eth0:网卡名称 设置网卡开机启动 vi /etc/sysconfig/network-scripts/ifcfg-eth0 ONBOOT=yes

  10. 访问网页全过程,用wireshark抓包分析

    用wireshark抓包查看访问网站过程 打开wireshark,打开一个无痕浏览器,输入网址,到网页呈现这一过程,网络数据包传递的消息都会被放在wireshark里.针对这些包,我们可以逐一分析,摸 ...