from __future__ import annotations# 用于显示进度条# from tqdm import tqdmfrom tqdm.notebook import tqdm as tqdm# 用于发起网络请求import requests# import signal### signal.signal(signal.SIGINT, multitasking.killall)# 请求头headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE'}# 定义 1 MB 多少为 BMB = 1024 ** 2def split(start: int, end: int, step: int) -> list[tuple[int, int]]:# 分多块parts = [(start, min(start + step, end))for start in range(0, end, step)]return partsdef get_file_size(url: str, raise_error: bool = False) -> int:'''获取文件大小Parameters----------url : 文件直链raise_error : 如果无法获取文件大小,是否引发错误Return------文件大小(B为单位)如果不支持则会报错'''response = requests.head(url)file_size = response.headers.get('Content-Length')if file_size is None:if raise_error is True:raise ValueError('该文件不支持多线程分段下载!')return file_sizereturn int(file_size)def download_multitask(url: str, file_name: str, retry_times: int = 3, each_size=16 * MB) -> None:# 用于多线程操作import multitasking# 导入 retry 库以方便进行下载出错重试from retry import retry'''根据文件直链和文件名下载文件Parameters----------url : 文件直链file_name : 文件名retry_times: 可选的,每次连接失败重试次数Return------None'''f = open(file_name, 'wb')file_size = get_file_size(url)@retry(tries=retry_times)@multitasking.taskdef start_download(start: int, end: int) -> None:'''根据文件起止位置下载文件Parameters----------start : 开始位置end : 结束位置'''_headers = headers.copy()# 分段下载的核心_headers['Range'] = f'bytes={start}-{end}'# 发起请求并获取响应(流式)response = session.get(url, headers=_headers, stream=True)# 每次读取的流式响应大小chunk_size = 128# 暂存已获取的响应,后续循环写入chunks = []for chunk in response.iter_content(chunk_size=chunk_size):# 暂存获取的响应chunks.append(chunk)# 更新进度条bar.update(chunk_size)f.seek(start)for chunk in chunks:f.write(chunk)# 释放已写入的资源del chunkssession = requests.Session()# 分块文件如果比文件大,就取文件大小为分块大小each_size = min(each_size, file_size)# 分块parts = split(0, file_size, each_size)print(f'分块数:{len(parts)}')# 创建进度条bar = tqdm(total=file_size, desc=f'下载文件:{file_name}')for part in parts:start, end = partstart_download(start, end)# 等待全部线程结束multitasking.wait_for_tasks()f.close()bar.close()def download_singletask(url, file_name):# 导入requests 库# import requests# 导入 tqdm# from tqdm import tqdm, tqdm_notebook# from tqdm.notebook import tqdm as tqdm# 文件下载直链# url = 'https://ffmpeg.org/releases/ffmpeg-6.0.tar.xz'# 请求头headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36 QIHU 360SE'}# # file_name = 'ffmpeg-6.0.tar.xz'# # 发起 head 请求,即只会获取响应头部信息# head = requests.head(url, headers=headers)# # 文件大小,以 B 为单位# file_size = head.headers.get('Content-Length')# if file_size is not None:# file_size = int(file_size)response = requests.get(url, headers=headers, stream=True)# 一块文件的大小chunk_size = 1024file_size = response.headers['content-length']if file_size is not None:file_size = int(file_size)print(file_size)bar = tqdm(total=file_size, desc=f'下载文件 {file_name}')with open(file_name, mode='wb') as f:# 写入分块文件for chunk in response.iter_content(chunk_size=chunk_size):f.write(chunk)bar.update(chunk_size)# 关闭进度条bar.close()def download(url, file_name):# try:# # 用于多线程操作# import multitasking# # 导入 retry 库以方便进行下载出错重试# from retry import retry## download_multitask(url, file_name)# except Exception as e:download_singletask(url, file_name)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。