Python之断点续传下载及进度显示

发布时间 2023-09-06 12:08:50作者: 汗牛充栋

Python之断点续传下载及进度显示

某日,因工作需要下载大量OSGB数据, 下载链接来源于一个csv文件, 于是解析了csv文件然后下载。为了提高下载效率及进度显示,写了一份脚本。

环境

  • python 3.7
  • requests
  • csv

过程

解析csv

废话不多说, 先上代码:

def fetch_download_url(source):
    result = defaultdict(list)

    with open(source, encoding='utf-16') as fp:

        reader = csv.DictReader(fp, delimiter="\t")
        for row in reader:
            result[row['LOC_TC']].append(row['FILE_URL'])
    
    return result

代码逻辑简单, 打开csv文件, 通过csv模块解析指定列。 其中踩坑点在于文件编码, 笔者csv文件编码为UCS-2 LE BOM, 文件读取格式应设为utf-16。 utf-8与gbk都会报错。

下载

下载逻辑其实很简单, 一行代码:

requests.get('https://XXXXXXX')

断点续传

如果要做断点续传, 就需要用到流式传输:

resp = requests.get(url='https://XXXXXXX', stream=True)

设置关键字参数streamTrue

接下来将流数据写入到磁盘上:

with open(filepath, 'ab') as fp:
    for data in resp.iter_content(chunk_size=1024):
        fp.write(data)

以上代码通过iter_content按块下载,块大小由参数chunk_size指定,然后将下载后的数据库写入到文件中。

而要做到断点续传, 则需要指定下载的header

headers = {
            "Range": 'bytes=%d-' % total_size,
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/115.0.0.0 Safari/537.36 Edg/115.0.1901.203"
    }
resp = requests.get(url='https://XXXXXXX', stream=True, headers=headers)

其中的Range指定了下载的其实字节位,即从指定字节处开始下载。

连接池

通过以下代码可以修改默认连接池大小10, 从而提高下载效率。具体原理此处暂不展开。

session = requests.Session()
session.mount("%s://"%(url.split(":")[0],), requests.adapters.HTTPAdapter(pool_connections=20, pool_maxsize=20))
response = session.get(url, stream=True, headers=headers)

进度显示

先看源码:

def display_progress(actual_size, total_size, mode):
    print("\r\tprogress:", end="")
    if mode == 0:
        print( "▋" * (50 *total_size//actual_size),"{:>6.2f}%".format((total_size/actual_size)*100), end="")
    else:
        print("[%d/%d]"%(total_size,actual_size), end="")

进度显示最核心的点在于如何在固定行打印进度,以上代码保证其能在固定行打印进度的核心在于打印\r,即将光标移动到一行的开始,再次打印将覆盖上一次打印的字符。

然后通过实际运行状态打印符号及百分比。代码中进度乘以50表示, 每2%显示一格进度。

效果

download