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)
设置关键字参数stream
为True
。
接下来将流数据写入到磁盘上:
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%显示一格进度。