图片下载

streamlit python 哪个版本号 python stream流_断点续传

tqdm

tqdm是一个快速、扩展性强的进度条工具库,用户只需要封装任意的迭代器 tqdm(iterator),tqdm官方文档

对于爬虫进度的监控,这是个不错的工具。

requests模块实现下载

对于requests的网络请求返回结果中,当需要获取文本的时候我们会使用response.text获取文本信息,使用response.content获取字节流,比如下载图片保存到一个文件,而对于大个的文件我们就要采取分块读取的方式了。

第一步,我们需要设置requests.get的stream参数为True。 默认情况下是stream的值为false,它会立即开始下载文件并存放到内存当中,倘若文件过大就会导致内存不足的情况.当把get函数的stream参数设置成True时,它不会立即开始下载,当你使用iter_content或iter_lines遍历内容或访问内容属性时才开始下载。需要注意一点:文件没有下载之前,它也需要保持连接。

断点续传

所谓断点续传,也就是要从文件已经下载的地方开始继续下载。在以前版本的 HTTP 协议是不支持断点的,HTTP/1.1 开始就支持了。一般断点下载时会用到 header请求头的Range字段,这也是现在众多号称多线程下载工具(如 FlashGet、迅雷等)实现多线程下载的核心所在。

HTTP请求头Range

range是请求资源的部分内容(不包括响应头的大小),单位是byte,即字节,从0开始. 如果服务器能够正常响应的话,服务器会返回 206 Partial Content 的状态码及说明. 如果不能处理这种Range的话,就会返回整个资源以及响应状态码为 200 OK .(这个要注意,要分段下载时,要先判断这个)。

Range请求头格式

Range: bytes=start-end

Range头域

Range头域可以请求实体的一个或者多个子范围。例如,  
表示头500个字节:bytes=0-499  
表示第二个500字节:bytes=500-999  
表示最后500个字节:bytes=-500  
表示500字节以后的范围:bytes=500-  
第一个和最后一个字节:bytes=0-0,-1  
同时指定几个范围:bytes=500-600,601-999 

Range: bytes=10- :第10个字节及最后个字节的数据
Range: bytes=40-100 :第40个字节到第100个字节之间的数据.

注意,这个表示[start,end],即是包含请求头的start及end字节的,所以,下一个请求,应该是上一个请求的[end+1, nextEnd]

程序实现

这里的断点续传没有做过度复杂的实现,只是简单的在当前目录下进行的。

# -*- coding: utf-8 -*-
import requests
from tqdm import tqdm
import os
import time

# 用法一
def tqdm_demo():
    text = ""
    for char in tqdm(["a", "b", "c", "d"]):
        text = text + char
        time.sleep(0.5)
# 用法二

def tqdm_demo2():
    pbar = tqdm(["a", "b", "c", "d"])
    for char in pbar:
        time.sleep(0.5)
        pbar.set_description("Processing %s" % char)
# 手动控制运行
# tqdm.update()方法用于手动更新进度条,对读取文件之类的流操作非常有用。
def tqdm_demo3():
    with tqdm(total=100) as pbar:
        for i in range(10):
            pbar.update(10)
            time.sleep(0.5)


def download_from_url(url, dst):
    '''
    :param url:  下载地址
    :param dst:  文件名称
    :return:
    '''
    #发起网络请求
    response = requests.get(url, stream=True)
    #获取返回的文件的大小
    file_size = int(response.headers['content-length'])

    #判断当前目录中是否有该文件,如果有获取文件的大小,从而实现断点续传
    if os.path.exists(dst):
        first_byte = os.path.getsize(dst)
    else:
        first_byte = 0
    #如果文件大小已经超过了服务器返回的文件的大小,返回文件长度
    if first_byte >= file_size: #(4)
        return file_size
    #设置断点续传的位置
    header = {"Range": f"bytes=%s-%s"%(first_byte,file_size)}
    # desc :进度条的前缀
    # unit 定义每个迭代的单元。默认为"it",即每个迭代,在下载或解压时,设为"B",代表每个“块”。
    # unit_scale 默认为False,如果设置为1或者True,会自动根据国际单位制进行转换 (kilo, mega, etc.) 。比如,在下载进度条的例子中,如果为False,数据大小是按照字节显示,设为True之后转换为Kb、Mb。
    #total:总的迭代次数,不设置则只显示统计信息,没有图形化的进度条。设置为len(iterable),会显示黑色方块的图形化进度条。
    pbar = tqdm(total=file_size, initial=first_byte,unit='B', unit_scale=True, desc=dst)
    #发送网络请求
    req = requests.get(url, headers=header, stream=True) #(5)
    #这里的二进制需要采用追加的方式写入文件,不然无法实现断点续传
    with(open(dst, 'ab')) as f:
        for chunk in req.iter_content(chunk_size=1024): #(6)
            if chunk:
                #用于方便观察进度条,在下载大视频的时候去掉也能观察出来
                time.sleep(0.01)
                f.write(chunk)
                f.flush()
                pbar.update(1024)
    pbar.close()
    return file_size

if __name__ == '__main__':
    url = "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1551406646&di=a385cb186c0f1c2c45e5c49b4015e848&src=http://img18.3lian.com/d/file/201709/21/f498e01633b5b704ebfe0385f52bad20.jpg"
    download_from_url(url, "百度美女图片.jpg")
    #以下是tqdm实例
    tqdm_demo()
    tqdm_demo2()
    tqdm_demo3()