Используйте одну aiohttp.ClientSession и запустите десять задач скачивания конкурентно. Сохраняйте поток частями в папку image под UUID-именами, проверяя HTTP-статус и ограничивая размер.
Асинхронное скачивание изображений в Python‑проекте
Используйте одну aiohttp.ClientSession и запустите десять задач скачивания конкурентно. Сохраняйте поток частями в папку image под UUID-именами, проверяя HTTP-статус и ограничивая размер.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Создать небольшое Python‑приложение, которое:
- Параллельно загружает 10 картинок из сети;
- Сохраняет полученные файлы в директорию image, расположенную в корне проекта;
- Для загрузки использовать асинхронные инструменты (например, aiohttp и asyncio);
- При отсутствии папки image она должна быть создана автоматически;
- Каждое изображение сохранять под уникальным именем.
Ответ
Используйте одну aiohttp.ClientSession и запустите десять задач скачивания конкурентно. Сохраняйте поток частями в папку image под UUID-именами, проверяя HTTP-статус и ограничивая размер.
Пример для Python 3.11+, если файл скрипта лежит в корне проекта и urls содержит десять доверенных адресов:
import asyncio
from pathlib import Path
from uuid import uuid4
import aiohttp
ROOT = Path(__file__).resolve().parent / 'image'
LIMIT = 20 * 1024 * 1024
async def download(session, url):
temporary = ROOT / f'{uuid4().hex}.part'
try:
async with session.get(url) as response:
response.raise_for_status()
if not response.headers.get('Content-Type', '').startswith('image/'):
raise ValueError('Expected an image')
size = 0
with temporary.open('xb') as file:
async for chunk in response.content.iter_chunked(64 * 1024):
size += len(chunk)
if size > LIMIT:
raise ValueError('Image too large')
file.write(chunk)
destination = temporary.with_suffix('.img')
temporary.rename(destination)
return destination
except BaseException:
temporary.unlink(missing_ok=True)
raise
async def main(urls):
if len(urls) != 10:
raise ValueError('Expected ten URLs')
ROOT.mkdir(parents=True, exist_ok=True)
timeout = aiohttp.ClientTimeout(total=60)
async with aiohttp.ClientSession(timeout=timeout) as session:
async with asyncio.TaskGroup() as group:
tasks = [group.create_task(download(session, url)) for url in urls]
return [task.result() for task in tasks]
Вызов: asyncio.run(main(urls)). Сетевые операции конкурентны; небольшие записи в файл здесь синхронные, для медленного диска нужен отдельный файловый исполнитель. Расширение .img нейтральное; Content-Type не доказывает корректность изображения. Для недоверенных URL дополнительно нужна защита SSRF.
Источник: docs.aiohttp.org.