需求:有大量图片的url需要将其快速下载到本地
技术点:采用编写并发代码的库asyncio以及基于asyncio实现的HTTP框架aiohttp
pip install asyncio
pip install aiohttp
代码如下:
import json
import os
import requests
import aiohttp
import asyncio
image_save_dir = "images" # 要将下载的图片保存到的本地文件夹路径
image_url_list = [] # 要下载的image url元素组成的列表
cnt = 0 # 已下载到本地指定位置的图片数量
n_miss = 0 # 下载失败的图片数量
async def download_image(session, url):
global cnt
global n_miss
file_name = os.path.basename(url)
# 保存图片到指定位置
file_path = os.path.join(image_save_dir, file_name)
if not os.path.exists(file_path):
try:
async with session.get(url) as response:
if response.status == 200:
# 获取文件名
with open(file_path, 'wb') as file:
file.write(await response.read())
cnt += 1
if cnt % 100 == 0:
print("已下载{}/{}".format(cnt,len(image_url_list)))
else:
n_miss += 1
print(f'下载失败,状态码:{response.status}, 链接:{url}')
except Exception as e:
n_miss += 1
print(f'下载失败,链接:{url}, 错误:{str(e)}')
else:
cnt += 1
if cnt % 100 == 0:
print("已下载{}/{}".format(cnt,len(image_url_list)))
print("下载失败: ",n_miss)
async def main():
async with aiohttp.ClientSession() as session:
tasks = [download_image(session, url) for url in image_url_list]
await asyncio.gather(*tasks)
print("总图片数量: {}".format(len(image_url_list)))
print("下载成功: {}".format(cnt))
print("下载失败:{}".format(n_miss))
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
采用上述代码进行并行下载,速度比传统的串行下载提升了好几个数量级(实验了下载20w张图片也很快),但是要注意(1)可能的网络原因导致的后续图片下载失败(在网络连接可以的情况下多运行几次代码即可)以及(2)可能的由于并行等待时间不足等原因导致的图片下载不全(即下载到本地之后,图片有损无法打开),此时,建议再用以下代码进行检查并串行下载完之前下载后有损的图片:
import json
import os
from PIL import Image
import requests
# 一、检查图片下载情况
image_path_list = [] # 需要检查的图片路径组成的列表
err_imgs = [] # 下载到本地但是无法打开的图片名称组成的列表
n_miss = 0 # 没下载到本地的图片数量
n_err = 0 # 下载到本地但是无法打开的图片数量
for i in range(len(image_path_list)):
image_path = image_path_list[i]
try:
image = Image.open(image_path)
except:
err_imgs.append(os.path.basename(image_path))
n_err += 1
# print(image_path)
if not os.path.exists(image_path):
n_miss += 1
print("没下载到本地的图片数量: ", n_miss)
print("下载到本地但是无法打开的图片数量: ", n_err)
err_imgs = list(set(err_imgs))
print(err_imgs)
# 二、如果有下载到本地但是图片有损打不开的情况,进行串行下载
if n_err > 0:
image_url_list = [] # 待串行下载的图片url列表
image_save_dir = "save_dir" # 待下载到本地保存的图片文件夹路径
if not os.path.exists(image_save_dir):
os.mkdir(image_save_dir)
print(image_save_dir + ' maked')
for image_url in image_url_list:
response = requests.get(image_url)
# 检查响应状态码,确保请求成功
if response.status_code == 200:
# 获取图像数据
image_data = response.content
# 本地保存图像
with open(os.path.join(image_save_dir, os.path.basename(image_url)), 'wb') as file:
file.write(image_data)
print(os.path.join(image_save_dir, os.path.basename(image_url)))
else:
print("下载失败,HTTP响应状态码:", response.status_code)
标签:Python,image,并行,url,print,path,os,下载 From: https://www.cnblogs.com/fzucsx/p/17732086.html欢迎在评论区给出宝贵意见,交流学习