Библиотека aiohttp в Python — асинхронные HTTP-запросы

19 июня 2026
Автор

Антон Ларичев

Введение

Библиотека aiohttp — это основной инструмент для выполнения асинхронных HTTP-запросов в Python. В отличие от синхронной requests, aiohttp работает поверх asyncio и позволяет отправлять сотни запросов одновременно, не блокируя событийный цикл. Это критично для приложений, которые обращаются к множеству внешних API, парсят веб-страницы или строят микросервисную архитектуру.

В этой статье мы разберём установку aiohttp, работу с клиентскими сессиями, отправку различных типов запросов и организацию параллельных вызовов.

Установка aiohttp

Для начала работы установите библиотеку через pip:

pip install aiohttp

Для работы с асинхронными потоками данных рекомендуется также установить aiofiles:

pip install aiofiles

Клиентская сессия — основа работы

В aiohttp все запросы выполняются через объект ClientSession. Сессия управляет пулом соединений, cookies и заголовками. Важно использовать сессию как контекстный менеджер, чтобы соединения корректно закрывались.

import aiohttp
import asyncio

async def main():
    # Создаём сессию как контекстный менеджер
    async with aiohttp.ClientSession() as sessiya:
        async with sessiya.get("https://jsonplaceholder.typicode.com/posts/1") as otvet:
            # Получаем статус ответа
            print(f"Статус: {otvet.status}")
            # Читаем JSON-ответ
            dannye = await otvet.json()
            print(f"Заголовок: {dannye['title']}")

asyncio.run(main())

Не создавайте новую сессию для каждого запроса — это неэффективно. Одна сессия может обслуживать множество запросов, переиспользуя TCP-соединения.

GET-запросы

GET-запрос — самый распространённый тип запроса для получения данных:

import aiohttp
import asyncio

async def poluchit_polzovatelya(sessiya, user_id):
    url = f"https://jsonplaceholder.typicode.com/users/{user_id}"
    async with sessiya.get(url) as otvet:
        if otvet.status == 200:
            dannye = await otvet.json()
            return dannye
        else:
            print(f"Ошибка: {otvet.status}")
            return None

async def main():
    async with aiohttp.ClientSession() as sessiya:
        # Получаем данные пользователя
        polzovatel = await poluchit_polzovatelya(sessiya, 1)
        if polzovatel:
            print(f"Имя: {polzovatel['name']}")
            print(f"Email: {polzovatel['email']}")

asyncio.run(main())

Для передачи параметров запроса используйте аргумент params:

import aiohttp
import asyncio

async def poisk(sessiya, zapros, limit=10):
    params = {"q": zapros, "limit": limit}
    async with sessiya.get("https://api.example.com/search", params=params) as otvet:
        return await otvet.json()

async def main():
    async with aiohttp.ClientSession() as sessiya:
        rezultat = await poisk(sessiya, "python asyncio", limit=5)
        print(rezultat)

asyncio.run(main())

POST-запросы

Для отправки данных на сервер используются POST-запросы. aiohttp поддерживает отправку JSON, форм и файлов:

import aiohttp
import asyncio

async def sozdat_post(sessiya, zagolovok, tekst, avtor_id):
    # Отправка JSON-данных
    dannye = {
        "title": zagolovok,
        "body": tekst,
        "userId": avtor_id,
    }
    async with sessiya.post(
        "https://jsonplaceholder.typicode.com/posts",
        json=dannye,  # Автоматически сериализует в JSON
    ) as otvet:
        rezultat = await otvet.json()
        print(f"Создан пост с ID: {rezultat['id']}")
        return rezultat

async def main():
    async with aiohttp.ClientSession() as sessiya:
        noviy_post = await sozdat_post(
            sessiya,
            "Асинхронный Python",
            "Статья про aiohttp и asyncio",
            1,
        )
        print(noviy_post)

asyncio.run(main())

Если вы хотите глубже разобраться в асинхронных паттернах и научиться строить полноценные приложения на Python — приходите на наш большой курс Продвинутый Python. На курсе 171 урок и 22 упражнения, AI-тренажёры для практики 24/7, решение задач с живым ревью наставника, еженедельные встречи с менторами.

Заголовки и авторизация

Для работы с API часто требуется передавать токены и пользовательские заголовки:

import aiohttp
import asyncio

async def main():
    # Заголовки для всей сессии
    zagolovki = {
        "Authorization": "Bearer my_token_123",
        "Content-Type": "application/json",
    }

    async with aiohttp.ClientSession(headers=zagolovki) as sessiya:
        # Все запросы в этой сессии будут использовать эти заголовки
        async with sessiya.get("https://api.example.com/profile") as otvet:
            print(await otvet.json())

        # Можно переопределить заголовки для конкретного запроса
        async with sessiya.get(
            "https://api.example.com/data",
            headers={"X-Custom-Header": "значение"},
        ) as otvet:
            print(await otvet.json())

asyncio.run(main())

Параллельные запросы

Главное преимущество aiohttp — возможность выполнять множество запросов одновременно:

import aiohttp
import asyncio
import time

async def zagruzit_stranicu(sessiya, url):
    async with sessiya.get(url) as otvet:
        tekst = await otvet.text()
        return f"{url}: {len(tekst)} символов"

async def main():
    urls = [
        "https://jsonplaceholder.typicode.com/posts/1",
        "https://jsonplaceholder.typicode.com/posts/2",
        "https://jsonplaceholder.typicode.com/posts/3",
        "https://jsonplaceholder.typicode.com/users/1",
        "https://jsonplaceholder.typicode.com/users/2",
    ]

    nachalo = time.time()

    async with aiohttp.ClientSession() as sessiya:
        # Запускаем все запросы параллельно
        zadachi = [zagruzit_stranicu(sessiya, url) for url in urls]
        rezultaty = await asyncio.gather(*zadachi)

        for rezultat in rezultaty:
            print(rezultat)

    print(f"Время выполнения: {time.time() - nachalo:.2f} сек")

asyncio.run(main())

Ограничение количества одновременных запросов

При работе с большим количеством URL важно ограничивать число одновременных соединений, чтобы не перегрузить сервер:

import aiohttp
import asyncio

async def zagruzit_s_limitom(sessiya, semafor, url):
    async with semafor:
        # Семафор ограничивает число одновременных запросов
        async with sessiya.get(url) as otvet:
            dannye = await otvet.text()
            print(f"Загружено {url}: {len(dannye)} символов")
            return dannye

async def main():
    urls = [f"https://jsonplaceholder.typicode.com/posts/{i}" for i in range(1, 21)]

    # Ограничиваем до 5 одновременных запросов
    semafor = asyncio.Semaphore(5)

    # Также можно ограничить через TCPConnector
    konektor = aiohttp.TCPConnector(limit=10)

    async with aiohttp.ClientSession(connector=konektor) as sessiya:
        zadachi = [zagruzit_s_limitom(sessiya, semafor, url) for url in urls]
        rezultaty = await asyncio.gather(*zadachi)
        print(f"Загружено {len(rezultaty)} страниц")

asyncio.run(main())

Обработка ошибок и таймауты

В реальных приложениях сетевые запросы могут завершаться ошибками. Важно правильно их обрабатывать:

import aiohttp
import asyncio

async def nadejniy_zapros(sessiya, url, popytki=3):
    # Устанавливаем таймаут для запроса
    timeout = aiohttp.ClientTimeout(total=10)

    for popytka in range(popytki):
        try:
            async with sessiya.get(url, timeout=timeout) as otvet:
                otvet.raise_for_status()  # Выбросит исключение при 4xx/5xx
                return await otvet.json()
        except aiohttp.ClientResponseError as e:
            print(f"Ошибка HTTP {e.status} для {url}")
            if e.status >= 500 and popytka < popytki - 1:
                # Повторяем при серверных ошибках
                await asyncio.sleep(2 ** popytka)
                continue
            raise
        except asyncio.TimeoutError:
            print(f"Таймаут для {url}, попытка {popytka + 1}/{popytki}")
            if popytka < popytki - 1:
                await asyncio.sleep(1)
                continue
            raise
        except aiohttp.ClientError as e:
            print(f"Ошибка соединения: {e}")
            raise

    return None

async def main():
    async with aiohttp.ClientSession() as sessiya:
        try:
            dannye = await nadejniy_zapros(sessiya, "https://jsonplaceholder.typicode.com/posts/1")
            print(f"Получено: {dannye['title']}")
        except Exception as e:
            print(f"Не удалось получить данные: {e}")

asyncio.run(main())

Частые ошибки

  • Создание новой сессии на каждый запрос — это расточительно и медленно. Создавайте одну ClientSession и переиспользуйте её для всех запросов.
  • Забыть закрыть сессию — незакрытая сессия вызовет предупреждение Unclosed client session. Всегда используйте async with для автоматического закрытия.
  • Не ограничивать параллельные запросы — запуск тысяч запросов одновременно может привести к исчерпанию ресурсов или блокировке со стороны сервера. Используйте Semaphore или TCPConnector(limit=N).
  • Чтение тела ответа после закрытия контекста — тело ответа доступно только внутри async with sessiya.get(...) as otvet. После выхода из блока данные недоступны.

Частозадаваемые вопросы

Чем aiohttp лучше requests? requests — синхронная библиотека, которая блокирует поток при каждом запросе. aiohttp работает асинхронно, что позволяет выполнять сотни запросов параллельно в одном потоке. Для одиночных запросов requests проще, для массовых — aiohttp значительно быстрее.

Можно ли использовать aiohttp вместе с requests в одном проекте? Да, но не смешивайте их в одном контексте. Используйте aiohttp для асинхронных операций и requests для синхронных скриптов. Если нужно вызвать синхронную функцию из асинхронного кода, используйте asyncio.to_thread().

Как отправить файл через aiohttp? Используйте FormData для отправки multipart-форм с файлами: создайте объект aiohttp.FormData(), добавьте файл через метод add_field() и передайте в аргумент data метода post().

Заключение

Библиотека aiohttp — незаменимый инструмент для асинхронных HTTP-запросов в Python. Клиентские сессии, параллельные запросы через asyncio.gather(), контроль через семафоры и обработка ошибок с повторными попытками — всё это позволяет строить надёжные и быстрые сетевые приложения. Для закрепления навыков работы с асинхронными запросами и построения реальных проектов рекомендуем курс Продвинутый Python. В первых 3 модулях курса доступно бесплатное содержание, что позволяет познакомиться с асинхронными паттернами и понять структуру курса до покупки полного доступа.

Стрелочка влевоСинтаксис async/await в Python — как писать асинхронный код

Постройте личный план изучения Python до уровня Middle — бесплатно!

Python — часть карты развития Backend

  • step100+ шагов развития
  • lessons30 бесплатных лекций
  • lessons300 бонусных рублей на счет

Все гайды по Python

Как отправлять запросы с помощью requests в PythonПочему Python выводит значение без команды printКак работает команда print в PythonВозможности Python для автоматизации задачРабота с JSON в Python на примерахPython get — методы получения данныхКак находить и исправлять ошибки в PythonРабота с данными через API и внешние сервисыСтруктура и оформление кода PythonОсновы Django с PythonПолезные приёмы в Python для повседневной работыИспользование locals в Python для отладкиИнтеграция PHP и PythonКак выполнять HTTPS-запросы в PythonFastAPI Python — быстрый старт: создание REST API с нуляКак работать с API в Python
Ввод целого числа в PythonВедение логов в PythonУдаление данных в Python с помощью removeОбработка исключений с помощью try/except в PythonФункция super() в Python — как вызвать метод родителяСоздание собственных контекстных менеджеров в PythonРабота с символами программирования PythonРабота с переменной X в PythonРабота с классами в PythonКак скачать Python на компьютерПростая программа на Python для начинающихОсновы Python для тех, кто начинаетЧто нового в Python 3Поддерживается ли Python 2 и стоит ли его использоватьPython 1 — с чего начиналась история языкаКоманда python print - полное руководство по выводу данныхПравила именования переменных в PythonПользовательские исключения в PythonОсновы Python coreОписание объектов PythonНаследование классов в Python — основы и примерыМножественное наследование в Python — примеры и MROКонтекстный менеджер with в Python — как работает и зачем нуженКомментарии в Python — однострочные, многострочные и docstringКакой Python выбрать для установкиКак вывести целое число с помощью print в PythonКак установить Python на Windows macOS и LinuxКак пользоваться консолью PythonКак получить последний элемент в PythonКак найти значение в PythonКак настроить PythonКак использовать print для строк в PythonКак работает интерпретатор PythonИнструкция по работе с PythonБлок finally в обработке исключений PythonЦелые числа в PythonАбстрактные классы в Python — ABC и abstractmethod
Загрузка данных PythonУправление проектами на GitHub с PythonСоздание веб-приложений на Flask PythonСоздание бота на PythonСоздание интерфейсов Python QTСоздание игр с PygameСоздание GUI в PythonКак работать со словарями в PythonРабота с библиотеками через Python PackagingРабота со временем в Python при помощи модуля timePython name — особенности переменнойМатематические операции в Python с модулем mathPython listing — что это и как использоватьPytest — тестирование на Python: полное руководствоОбработка изображений с OpenCV PythonNumPy в Python — основы и применение в задачахМашинное обучение с PythonИспользование Anaconda с PythonМодуль contextlib в Python — утилиты для контекстных менеджеровБиблиотеки Python и их применение в проектах
Возврат значений из функции в PythonВложенные функции в PythonСоздание собственных декораторов в PythonРабота с функцией map в PythonЦикл while в Python и примеры использованияОбработка чисел, введённых через input в PythonОсновные операторы в Python с примерамиУсловные выражения if else в Python для начинающихКак выполняется вызов функций call в PythonПродвинутые генераторы в Python — send, throw, close и корутиныПозиционные и именованные аргументы в PythonОбъявление переменных и управление областью видимости в PythonПередача аргументов по ссылке и по значению в PythonПередача аргументов через args и kwargs в PythonОсновные методы Python и примеры их использованияОператор match/case в Python 3.10+ — основы структурного сопоставленияПаттерны match/case в Python — деструктуризация, guard и вложенные шаблоныПрактические примеры match/case в Python — реальные сценарии примененияЛокальные и глобальные переменные в PythonЧасто используемые команды PythonКлючевые слова global и nonlocal в PythonКак создавать функции в PythonКак работает сборщик мусора в PythonКак работает область видимости переменных в PythonКак работает функция callable в PythonКак работает функция any и all в PythonКак проверить тип переменной в PythonКак передать функцию как аргумент в PythonКак использовать функцию isinstance в PythonКак использовать функцию filter в PythonКак использовать функцию filter в PythonКак использовать функцию eval безопасно в PythonКак использовать декораторы в PythonИзменяемые и неизменяемые типы данных в PythonГенераторы и yield в Python — как создавать и использоватьГенераторные выражения в Python — синтаксис и примерыФункции в Python и способы их вызоваФункции как объекты в PythonЧто такое замыкания в PythonЧто делает функция reduce в PythonЧто делает функция id в PythonАргументы по умолчанию в PythonАнонимные функции и lambda в PythonАлгоритмы на Python — примеры и объяснение
Запись данных в PythonУстановка pip в PythonУправление зависимостями requirement в PythonУправление библиотеками с помощью Python PackagingУдаление пробелов с помощью strip в PythonСтруктурирование кода в PythonСоздание исполняемого файла Python в exeРазбор traceback в модуле PythonРазбор site-packages в PythonРазбор Program Files в PythonРабота с Unicode кодировками в PythonРабота с системными функциями Python sysРабота с папкой AppData в PythonРабота с модулем logging в PythonРабота с каталогами в PythonРабота с CSV в PythonВиртуальная среда venv в Python — создание и настройкаКак создать простое приложение на PythonИспользование pip в Python для установки пакетовМодули в Python и организация кода в проектеИмпорт модулей в Python и правила подключенияРабота с файлами в Python пошаговоЧто делает компилятор Python и как он работаетПолучение строки из модуля PythonПодключение файлов в Python с includeПеременные среды в PythonСборка проекта с помощью packaging в PythonНастройка Python сервераИспользование Python на UbuntuИспользование консоли PythonИспользование кодировок в PythonИнициализация пакетов PythonИмпорт модулей PythonИмпорт имен в PythonСреда IDLE Python и базовые возможностиЧтение и запись TXT в PythonЧтение файлов в Python с помощью open file
Удаление элементов из списка PythonТипы данных в Python — обзор и рекомендацииОсновные операции со строками в PythonМетоды str в Python и обработка текстаСписки в Python и их ключевые методыСоздание списков данных в PythonРабота со строками и символами в PythonРабота со столбцами в PythonРабота со списком значений в PythonРабота с таблицами в Python с помощью DataFrameРабота с RFR в PythonРабота с пробелами в PythonРабота с массивами в PythonРабота с кортежами tuple PythonРабота с координатами X и Y в PythonРабота с ключами в PythonРабота с элементами данных PythonРабота с двоичными числами PythonРабота с данными в PythonРабота с данными NumPy PythonРабота с большими числами в PythonРабота с битами в PythonРабота с байтами в PythonЧто такое значение в Python и как его определитьМножества в Python и операции с нимиИспользование range в Python для цикловПроверка на четность в PythonПроверка числа в PythonПреобразование типов в PythonПреобразование списка в строку PythonПреобразование числа в строку в PythonПостроение графиков в PythonОпределение индекса элемента в PythonОкругление чисел в PythonОбъединение списков в Python с помощью zipМножества в PythonМассивы в Python и отличие от списковМассив чисел в PythonКортежи данных в PythonКак вычислить сумму чисел в PythonКак получить остаток от деления в PythonКак найти следующее число в PythonИспользование Unicode в PythonТип int в Python и его особенностиИндекс списка в PythonФункции для работы со строками в PythonЭлементы Python и способы доступа к нимДоступ к элементам массива в PythonДеление чисел в PythonРабота с данными в Python на практикеКак работать с числами в Python
Открыть базу знаний

Лучшие курсы по теме

Иконка молнииНовый
изображение курса

Основы Python

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Nest.js с нуля

Антон Ларичев
AI-тренажерыAI-тренажеры
Практика в студииПрактика в студии
Гарантия
Бонусы
иконка звёздочки рейтинга4.6
3 999 ₽ 6 990 ₽
Подробнее
изображение курса

Docker и Ansible

Антон Ларичев
AI-тренажерыAI-тренажеры
Гарантия
Бонусы
иконка звёздочки рейтинга4.7
3 999 ₽ 6 990 ₽
Подробнее

Отправить комментарий