Python · API · Продвинутый уровень
Асинхронные запросы с httpx
Используйте httpx с asyncio для параллельных запросов к API и ускорения скриптов с несколькими вызовами.
Краткое введение в тему и пояснения перед упражнениями (упражнения ниже):
Практические примеры asyncio.gather
#Справочник httpx и asyncio
#Упражнения:
Первый асинхронный запрос
#Напишите асинхронную функцию с httpx.AsyncClient, которая получает /api/products/ и выводит количество продуктов. Запустите её через asyncio.run().
import httpx
import asyncio
BASE_URL = 'https://apilearn.tukas.dev'
async def fetch_products():
# Используйте httpx.AsyncClient чтобы получить /api/products/
pass
asyncio.run(fetch_products())
Решение
import httpx
import asyncio
BASE_URL = 'https://apilearn.tukas.dev'
async def fetch_products():
async with httpx.AsyncClient() as client:
response = await client.get(f'{BASE_URL}/api/products/')
data = response.json()
print(data['count'])
asyncio.run(fetch_products())
Параллельные запросы с gather
#Используйте asyncio.gather() чтобы сделать два запроса параллельно: GET /api/products/ и GET /api/categories/. Выведите общее количество продуктов и количество категорий.
import httpx
import asyncio
BASE_URL = 'https://apilearn.tukas.dev'
async def main():
async with httpx.AsyncClient() as client:
# Сделайте оба запроса параллельно через gather
pass
asyncio.run(main())
Решение
import httpx
import asyncio
BASE_URL = 'https://apilearn.tukas.dev'
async def main():
async with httpx.AsyncClient() as client:
products_resp, categories_resp = await asyncio.gather(
client.get(f'{BASE_URL}/api/products/'),
client.get(f'{BASE_URL}/api/categories/'),
)
print(products_resp.json()['count'])
print(len(categories_resp.json()))
asyncio.run(main())
Получить несколько продуктов параллельно
#Напишите корутину fetch_product(client, product_id), которая получает /api/products/{id}/. Используйте asyncio.gather() чтобы получить продукты с id от 1 до 5 одновременно. Выведите название и цену каждого.
import httpx
import asyncio
BASE_URL = 'https://apilearn.tukas.dev'
async def fetch_product(client, product_id):
# GET /api/products/{product_id}/
pass
async def main():
async with httpx.AsyncClient() as client:
# Соберите и выполните 5 запросов через gather
pass
asyncio.run(main())
Решение
import httpx
import asyncio
BASE_URL = 'https://apilearn.tukas.dev'
async def fetch_product(client, product_id):
response = await client.get(f'{BASE_URL}/api/products/{product_id}/')
return response.json()
async def main():
async with httpx.AsyncClient() as client:
products = await asyncio.gather(*[
fetch_product(client, i) for i in range(1, 6)
])
for p in products:
print(p['name'], p['price'])
asyncio.run(main())
Авторизованный асинхронный клиент
#Используйте httpx.AsyncClient с заголовком авторизации (полученным через синхронный requests.post). Сделайте параллельные GET к /api/cart/ и /api/users/profile/. Выведите username и количество товаров в корзине.
import httpx import asyncio import requests BASE_URL = 'https://apilearn.tukas.dev' # 1. Получите токен через requests (синхронно) # 2. Используйте AsyncClient с заголовком Authorization # 3. Параллельно получите профиль и корзину
Решение
import httpx
import asyncio
import requests
BASE_URL = 'https://apilearn.tukas.dev'
token = requests.post(f'{BASE_URL}/api/auth/token/', json={
'username': 'ВАШ_ЛОГИН', 'password': 'ВАШ_ПАРОЛЬ',
}).json()['token']
async def main():
headers = {'Authorization': f'Token {token}'}
async with httpx.AsyncClient(headers=headers) as client:
profile_resp, cart_resp = await asyncio.gather(
client.get(f'{BASE_URL}/api/users/profile/'),
client.get(f'{BASE_URL}/api/cart/'),
)
print(profile_resp.json()['username'])
print(len(cart_resp.json()['items']))
asyncio.run(main())
Сравнение последовательного и параллельного выполнения
#Измерьте время выполнения двух подходов для получения продуктов 1-5: сначала с requests в цикле (последовательно), затем с httpx и asyncio.gather (параллельно). Выведите время для обоих вариантов.
import httpx
import asyncio
import requests
import time
BASE_URL = 'https://apilearn.tukas.dev'
# Подход 1: последовательный с requests
start = time.time()
# ... ваш код ...
print(f'Последовательный: {time.time() - start:.2f}s')
# Подход 2: параллельный с httpx
start = time.time()
# ... ваш код ...
print(f'Параллельный: {time.time() - start:.2f}s')
Решение
import httpx
import asyncio
import requests
import time
BASE_URL = 'https://apilearn.tukas.dev'
# Подход 1: последовательный
start = time.time()
for i in range(1, 6):
requests.get(f'{BASE_URL}/api/products/{i}/')
print(f'Последовательный: {time.time() - start:.2f}s')
# Подход 2: параллельный
async def fetch(client, i):
return await client.get(f'{BASE_URL}/api/products/{i}/')
async def parallel():
async with httpx.AsyncClient() as client:
await asyncio.gather(*[fetch(client, i) for i in range(1, 6)])
start = time.time()
asyncio.run(parallel())
print(f'Параллельный: {time.time() - start:.2f}s')