Я пытаюсь написать несколько асинхронных GET-запросов с пакетом aiohttp, и выяснил большинство частей, но мне интересно, каков стандартный подход при обработке сбоев (возвращаемых как исключения).
Общая идея моего кода до сих пор (после некоторых проб и ошибок я следую подходу здесь ):
import asyncio
import aiofiles
import aiohttp
from pathlib import Path
with open('urls.txt', 'r') as f:
urls = [s.rstrip() for s in f.readlines()]
async def fetch(session, url):
async with session.get(url) as response:
if response.status != 200:
response.raise_for_status()
data = await response.text()
# (Omitted: some more URL processing goes on here)
out_path = Path(f'out/')
if not out_path.is_dir():
out_path.mkdir()
fname = url.split("/")[-1]
async with aiofiles.open(out_path / f'{fname}.html', 'w+') as f:
await f.write(data)
async def fetch_all(urls, loop):
async with aiohttp.ClientSession(loop=loop) as session:
results = await asyncio.gather(*[fetch(session, url) for url in urls],
return_exceptions=True)
return results
if __name__ == '__main__':
loop = asyncio.get_event_loop()
results = loop.run_until_complete(fetch_all(urls, loop))
Теперь все работает нормально:
- Как и ожидалось, переменная
results
заполняется записями None
, где соответствующий URL [т.е. с тем же индексом в переменной массива urls
, т.е. с тем же номером строки во входном файле urls.txt
] былуспешно запрошен, и соответствующий файл записан на диск. - Это означает, что я могу использовать переменную результатов, чтобы определить, какие URL не были успешными (эти записи в
results
не равны None
)
Я ознакомился с несколькими руководствами по использованию различных асинхронных пакетов Python (aiohttp
, aiofiles
и asyncio
), но я не видел стандартного способаобработайте этот последний шаг.
- Должна ли повторная попытка отправить запрос GET после того, как оператор
await
завершил / завершил? - ... или долженповторная попытка отправить запрос GET инициируется каким-либо обратным вызовом при сбое
- Ошибки выглядят следующим образом:
(ClientConnectorError(111, "Connect call failed ('000.XXX.XXX.XXX', 443)")
то есть запрос на IP-адрес 000.XXX.XXX.XXX
в порту 443
завершился неудачей, вероятно, потомунекоторый предел от сервера, который я должен соблюдать, ожидая с тайм-аутом перед повторной попыткой.
- Есть ли какой-то тип ограничения, который я мог бы рассмотреть, чтобы установить количество запросов, а непробуете их все?
- Я получаю около 40-60 успешных запросов при попытке нескольких сотен (более 500) URL-адресов в моем списке.
Наивно я ожидал run_until_complete
, чтобы обработать это таким образом, чтобы он завершил работу при запросе всех URL, но это не так.
Я не работал с асинхронным Python и сессиями / цикламидо, поэтому был бы признателен за любую помощь, чтобы найти, как получить results
.Пожалуйста, дайте мне знать, если я могу дать больше информации, чтобы улучшить этот вопрос, спасибо!