python进度条下载文件

python进度条下载文件

异步进度条:asyncio

环境:python3.7
库:需要安装aiohttp,tqdm,resquests
import asyncio
import aiohttp
from tqdm import tqdm


async def down_video(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(video_url, headers=headers) as resp:
            # 获取文件大小
            try:
                # 创建一个进度条,total文件长度,unit_scale=True设置显示下载速度k和m,ascii=True:windows控制台不换行,desc进度条前面的描述
                with tqdm(total=content_length, unit='', desc=f'下载:{name}', unit_divisor=1024, ascii=True, unit_scale=True) as bar:
                    content_length = resp.headers['content-length']
                    with open('文件名', 'rb+') as f:
                        # 一段一段的下载
                        async for chunk in resp.content.iter_chunked(1024):
                            f.write(chunk)
                            # 更新进度条
                            bar.update(len(chunk))
            except:
                print('文件不支持')
            

同步进度条resquests

import requests
from contextlib import closing
from tqdm import tqdm
# 设置stream=True为了不马上请求  colsing用来使用with管理上下文,不使用要关闭response
with closing(requests.get(video_url, stream=True, headers=headers)) as response:
    # 文件长度
    content_length = resp.headers['content-length']
    with open('文件名', 'rb+') as f:
        # 和前面的一样
        with tqdm(total=content_length, unit='', ascii=True, unit_scale=True) as bar:
            # 每次请求长度1024*10
            for chunk in response.iter_content(chunk_size=1024*10):
                if chunk:
                    f.write(chunk)
                    # 更新进度条
                    bar.update(1024*10)      

多协程asyncio


import asyncio
import aiohttp
from tqdm import tqdm
import os


class down_video():
    def __init__(self, headers=''):
        # 请求头
        self.__headers = headers

    def set_headers(self, new_headers):
        # 设置请求头
        self.__headers = new_headers

    async def __down_video(self, session, path, video_url, start, headers, bar):
        """
        :param path: 保存位置+名字
        :param session:
        :param video_url: 视频地址
        :param start: 视频开始写入位置
        :param headers: 请求头,包含请求长度和位置
        :param bar: 进度条
        """
        async with session.get(video_url, headers=headers) as resp:
            with open(path, 'rb+') as f:
                # 写入位置,指针移到指定位置
                f.seek(start)
                async for b in resp.content.iter_chunked(1024 * 1024):
                    f.write(b)
                    # 更新进度条,每次请求得到的长度
                    bar.update(len(b))

    async def __get_length(self, session, path, video_url):
        """创建和视频大小一样文件,并返回视频长度"""
        async with session.get(video_url, headers=self.__headers) as resp:
            # 获取视频长度
            le = int(resp.headers['Content-Length'])
            f = open(path, 'wb')
            f.truncate(le)
            f.close()
            return le

    async def __start_async(self, video_url, path, count=32):
        """
        :param video_url:视频地址
        :param path: 视频保存位置
        :param count:协程数量
        """
        path_, name = os.path.split(path)
        # 判断目录是否存在
        if not os.path.exists(path_):
            print('创建文件夹', path_)
            os.mkdir(path_)
        async with aiohttp.ClientSession() as session:
            # 文件长度
            content_length = await self.__get_length(session, path, video_url=video_url)
            
            # 每个协程爬取长度
            size = content_length // count
            args_list = []
            for i in range(count):
                start = i * size
                # 最后一个
                if i == count - 1:
                    end = content_length
                else:
                    end = start + size
                if start > 0:
                    start += 1
                # 设置请求视频位置
                headers = {
                    'Range': f'bytes={start}-{end}'
                }
                # 合并请求头
                headers.update(self.__headers)
                args = [session, path, video_url, start, headers]
                args_list.append(args)
            
            if args_list:
            	# total视频长度
                with tqdm(total=content_length, unit='', desc=f'下载:{name}', unit_divisor=1024, ascii=True,
                          unit_scale=True) as bar:
                    # 开始协程
                    await asyncio.wait([self.__down_video(*args, bar) for args in args_list])
            else:
                print('异常,有可能是请求头问题,或者视频地址不对,或者别的')

                
    def main(self, video_url, path, count=32):
        """
        :param video_url: 视频地址
        :param path: 保存地址
        :param count: 协程数量
        """
        asyncio.run(self.__start_async(video_url, path, count))


if __name__ == '__main__':
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:67.0) Gecko/20100101 Firefox/67.0'
    }
    # 视频真实地址
    video_url = ''
    # 文件路径
    path = '3.flv'
    dv = down_video()
    # 设置请求头
    dv.set_headers(headers)
    # 开始
    dv.main(video_url, path)

效果

在这里插入图片描述

ps:下载前面速度还可以,后面就············

你可能感兴趣的:(python进度条下载文件)