【代码】Python使用requests下载文件时获取下载进度与实时速度

正文

使用requests, multiprocessing, time等库,代码如下,提供的注释供参考:

from contextlib import closing
import requests, os
import time, multiprocessing
from multiprocessing import Process


# 通过多进程实现实时速度显示
def download(download_url, download_path, headers):
    file_name = os.path.basename(download_path)
    with closing(requests.get(download_url, timeout=10, verify=False, stream=True, headers=headers)) as response:
        chunk_size = 1024                                       # 单次请求最大值
        content_size = int(response.headers['content-length'])  # 文件总大小

        with multiprocessing.Manager() as mng:  # 通过Manager向定时显示进程传递信息
            mdict = mng.dict()
            mdict['data_bytes'] = 0    # 当前下载字节数
            mdict['exit'] = False      # 进程是否继续
            process = Process(target=cron, args=(file_name, content_size, mdict))   # 生成进程对象,执行显示函数

            # 开始下载
            process.start()
            with open(download_path, "wb") as file:
                for data in response.iter_content(chunk_size=chunk_size):   # 每取满chunk_size字节即存储
                    file.write(data)
                    mdict['data_bytes'] += len(data)
            # 下载完毕
            mdict['exit'] = True
            process.join(3)     # 3秒超时时间,显示完全
            process.terminate() # 超时时直接终止


def cron(file_name, content_size, mdict):   # 显示任务函数
    interval = 0.5      # 执行间隔

    content_size_formated = format_bytes_num(content_size)  # 文件总大小转换为恰当显示格式
    data_bytes_prev = mdict['data_bytes']   # 计算字节增量所需
    time_prev = time_now = time.time()      # 初值
    while True:     # 显示循环
        data_bytes = mdict['data_bytes']            # 当前下载字节数
        # 速度计算
        try: speed_num = (data_bytes - data_bytes_prev) / (time_now - time_prev)
        except ZeroDivisionError: speed_num = 0
        data_bytes_prev = data_bytes    # 存储当前字节数作为下次计算的参照
        time_prev = time_now            # 存储当前时间作为下次计算的参照

        # 显示
        speed = format_bytes_num(speed_num)
        data_bytes_formated = format_bytes_num(data_bytes)
        persent = data_bytes / content_size * 100   # 当前下载百分比
        done_block = '█' * int(persent // 2)        # 共显示50块,故以2除百作五十,计为所下载的显示块数
        print(f"\r {file_name} ----> [{done_block:50}] {persent:.2f}%   {speed}/s   {data_bytes_formated}/{content_size_formated}", end=" ")

        # 收到信号时退出
        if mdict['exit']: break

        # 消磨剩余时间
        time_now = time.time()
        sleep_time = time_prev + interval - time_now
        if sleep_time > 0:
            time.sleep(sleep_time)
            time_now = time.time()  # 避免误差


def format_bytes_num(bytes_num):    # 格式化为合适的数值大小与单位
    i = 0
    while bytes_num > 1024 and i < 9 - 1:
        bytes_num /= 1024
        i += 1
    unit = ('B', 'kiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB')[i]
    return "%.2f" % bytes_num + unit

 

输出类似于:

你可能感兴趣的:(python,开发语言)