Python 使用Asyncio和Aiohttp下载数千个图像

Python 使用Asyncio和Aiohttp下载数千个图像,python,asynchronous,python-asyncio,aiohttp,timeoutexception,Python,Asynchronous,Python Asyncio,Aiohttp,Timeoutexception,我一直在尝试在本地文件系统中下载数千个图像,但它没有正常工作,因为我在下载了大约5000个由目录分隔的图像时遇到了一个名为asyncio.exceptions.TimeoutError的异常 第一次执行下一个脚本时,我下载了16.000个,但每次执行它,下载的图像数量就会减少,目前我大约有5000个图像 这就是我实现的脚本: 导入操作系统 导入异步 导入文件 导入异步\u超时 从aiohttp导入客户端会话 从生成器导入生成\u散列 从记录器导入记录器 从键入导入列表、Dict、任意 异步def

我一直在尝试在本地文件系统中下载数千个图像,但它没有正常工作,因为我在下载了大约5000个由目录分隔的图像时遇到了一个名为asyncio.exceptions.TimeoutError的异常

第一次执行下一个脚本时,我下载了16.000个,但每次执行它,下载的图像数量就会减少,目前我大约有5000个图像

这就是我实现的脚本:

导入操作系统
导入异步
导入文件
导入异步\u超时
从aiohttp导入客户端会话
从生成器导入生成\u散列
从记录器导入记录器
从键入导入列表、Dict、任意
异步def下载_文件(会话:任意,远程_url:str,文件名:str)->无:
尝试:
异步与异步超时。超时(120):
与会话.get(远程url)异步作为响应:
如果response.status==200:
将aiofiles.open(文件名,mode='wb')作为f进行异步:
响应中数据的异步.content.iter\u分块(1024):
等待f写入(数据)
其他:
error(f“从远程服务器获取{filename}的错误”)
除asyncio.TimeoutError外:
logger.error(f“将{filename}下载到本地服务器的超时错误”)
提升
异步def下载_文件(图像:List[Dict[str,Any]],路径:str)->无:
headers={“用户代理”:“Mozilla/5.0(兼容;Googlebot/2.1+http://www.google.com/bot.html)"}
与ClientSession(headers=headers)异步作为会话:
tasks=[asyncio.sure_future(为图像中的图像下载_文件(会话,图像['resource'],获取_文件名(图像,路径))]
等待asyncio.gather(*任务)
def下载图片(图片:列表[Dict[str,Any]],路径:str)->无:
尝试:
loop=asyncio.get\u event\u loop()
future=asyncio。确保未来(下载文件(图像、路径))
循环。运行_直到_完成(未来)
logger.info(f'远程服务器的图像已成功下载')
除异常作为错误外:
error(从远程服务器下载映像时出错:{error})
提升
def get_文件名(图像:Dict[str,Any],路径:str)->str:
图像_dir='{}/{}'。格式(路径,图像['id'])
image_file='{}.jpg'.格式(生成_散列(image['resource']))
如果操作系统路径不存在(图像目录):
os.makedirs(图像目录)
返回os.path.join(图像目录,图像文件)
def main():
图像=[
{
“id”:“10755431”,
'资源':'http://image1.jpg'
}, 
{
'id':'10755432',
'资源':'http://image2.jpg'
}, 
{
“id”:“101426201”,
'递归':'http://image3.jpg'
}
]
图像路径='/home/stivenramireza'
下载图片(图片、图片路径)
如果名称=“\uuuuu main\uuuuuuuu”:
main()
我得到了这个错误:

错误:root:将/home/stivenramireza/10755431/664e3bdd10cd6945274f38ec822a9eb.jpg下载到本地服务器时出现超时错误
错误:root:从远程服务器下载图像时出错:
回溯(最近一次呼叫最后一次):
下载文件第17行的文件“/home/stivenramireza/storage/main.py”
响应中数据的异步.content.iter\u分块(1024):
文件“/home/stivenramireza/.local/lib/python3.8/site packages/aiohttp/streams.py”,第39行,在__
rv=等待自我读取函数()
文件“/home/stivenramireza/.local/lib/python3.8/site packages/aiohttp/streams.py”,第368行,已读
等待自我
文件“/home/stivenramireza/.local/lib/python3.8/site packages/aiohttp/streams.py”,第296行,在等待中
侍者
asyncio.exceptions.CancelleError
在处理上述异常期间,发生了另一个异常:
回溯(最近一次呼叫最后一次):
文件“main.py”,第70行,在
main()
文件“main.py”,第67行,在main中
下载图片(图片、图片路径)
下载图片中的第34行文件“/home/stivenramireza/storage/main.py”
循环。运行_直到_完成(未来)
文件“/usr/lib/python3.8/asyncio/base\u events.py”,第616行,运行直到完成
返回future.result()
下载文件中第28行的文件“/home/stivenramireza/storage/main.py”
等待asyncio.gather(*[asyncio.Sure_future(为图像中的图像下载文件(会话,图像['recurso'],获取文件名(图像,路径))))
文件“/home/stivenramireza/storage/main.py”,第20行,在下载文件中
error(f“从Re服务器获取{filename}的错误”)
文件“/home/stivenramireza/.local/lib/python3.8/site packages/async_timeout/_init__.py”,第55行,在_aexit中__
自动退出(exc类型)
文件“/home/stivenramireza/.local/lib/python3.8/site packages/async\u timeout/\uuuuuu init\uuuuuuuuu.py”,第92行,在退出时
引发asyncio.TimeoutError
asyncio.exceptions.TimeoutError
我该怎么办


提前感谢。

您的
下载文件
函数捕获超时错误,并重新引发它。您的
download\u files
函数使用
asyncio.gather()
,它在第一个异常时退出并将其传播给调用方。有理由假设,当下载大量文件时,其中一个文件迟早会超时,在这种情况下,整个程序会中断

我该怎么办

这取决于您希望程序在超时情况下执行的操作。例如,您可能想要重试该文件,或者您可能想要放弃。但是您很可能不想因为一个文件超时而中断整个下载

虽然在许多情况下,重新引发您捕获的异常是正确的做法,但这并不是正确的做法。您可以将
download_file
末尾的
raise
更改为
return(re