Работа с API в языке Python: инструменты и подходы
Введение в API запросы на Python
API (Application Programming Interface) позволяет программам обмениваться данными. В Python существует несколько библиотек для выполнения HTTP-запросов. Наиболее популярное и эффективное решение для синхронных запросов - библиотека requests. Она предоставляет удобный интерфейс для работы с методами GET, POST, PUT, DELETE и обработки ответов.
Базовое решение: библиотека requests
Установка: pip install requests
import requests
# GET запрос
response = requests.get('https://api.github.com/users/octocat')
print(response.status_code) # 200
print(response.json()['login']) # octocatApi python (api в python)
Пояснение: response.status_code содержит код ответа, response.json() десериализует JSON в словарь Python. Типичная проблема: игнорирование проверки статуса. Решение: использовать response.raise_for_status().
Частая ошибка: потеря соединения при большом количестве запросов
При выполнении множества запросов без повторного использования соединения может возникнуть ошибка ConnectionError. Используйте объект Session:
with requests.Session() as session:
for i in range(10):
resp = session.get('https://httpbin.org/get')
print(resp.status_code)Сессия автоматически управляет пулом соединений и cookie.
POST запрос с данными
payload = {'key1': 'value1', 'key2': 'value2'}
response = requests.post('https://httpbin.org/post', data=payload)
print(response.json())Для отправки JSON используйте параметр json:
import json
data = {'username': 'test', 'password': 'pass'}
response = requests.post('https://httpbin.org/post', json=data)
print(response.json()['json'])Как сделать асинхронные запросы для ускорения работы?
Вариант A: httpx - современная замена requests с поддержкой async/await
Установка: pip install httpx. httpx поддерживает как синхронный, так и асинхронный режимы.
import httpx
async def fetch(url):
async with httpx.AsyncClient() as client:
resp = await client.get(url)
return resp.status_code
# Запуск асинхронно
import asyncio
async def main():
status = await fetch('https://httpbin.org/get')
print(status)
asyncio.run(main())При работе с асинхронным кодом часто забывают использовать await, что приводит к предупреждению или ошибке. Всегда проверяйте, что вызовы HTTP сопровождаются await внутри асинхронной функции.
Как выполнять запросы без сторонних библиотек?
Вариант B: urllib - встроенная библиотека
from urllib.request import urlopen
from urllib.parse import urlencode
params = urlencode({'q': 'python'})
url = f'https://httpbin.org/get?{params}'
with urlopen(url) as response:
data = response.read()
print(data.decode('utf-8')[:100])Недостаток: больше кода для обработки ошибок и JSON. Типичная проблема: нужно закрывать соединение вручную, но контекстный менеджер решает это.
Как сделать параллельные асинхронные запросы с максимальной производительностью?
Вариант C: aiohttp - асинхронная библиотека для высоконагруженных систем
import aiohttp
import asyncio
async def fetch(session, url):
async with session.get(url) as resp:
return await resp.json()
async def main():
urls = ['https://api.github.com/users/octocat'] * 5
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
for r in results:
print(r['login'])
asyncio.run(main())Важно: создавать одну сессию для всех запросов, иначе производительность упадет. Типичная ошибка: не закрывать сессию - используйте async with.
Расширенные примеры работы с API
Пример 1: Пагинация через requests с обработкой ссылок
import requests
def fetch_all_pages(base_url):
results = []
url = base_url
while url:
response = requests.get(url)
response.raise_for_status()
data = response.json()
results.extend(data.get('items', []))
# Извлечение URL следующей страницы из заголовка Link
link_header = response.headers.get('Link', '')
if 'rel="next"' in link_header:
# Парсинг простого формата ; rel="next"
parts = link_header.split(',')
for part in parts:
if 'rel="next"' in part:
url = part.split(';')[0].strip(' <>')
break
else:
url = None
return results
# Пример GitHub API
items = fetch_all_pages('https://api.github.com/search/repositories?q=python&per_page=2')
print(f'Всего получено: {len(items)} репозиториев') Всего получено: 10 репозиториев (зависит от количества)
Пример 2: Отправка файла через multipart/form-data с httpx
import httpx
# Создаем тестовый файл
with open('test.txt', 'w') as f:
f.write('Hello World')
async def upload_file():
async with httpx.AsyncClient() as client:
files = {'file': open('test.txt', 'rb')}
response = await client.post('https://httpbin.org/post', files=files)
print(response.json()['files'])
import asyncio
asyncio.run(upload_file()){'file': 'Hello World'}Пример 3: Обработка rate limiting с повторными попытками (retry)
import requests
from requests.adapters import HTTPAdapter
from urllib3.util.retry import Retry
session = requests.Session()
retries = Retry(total=3, backoff_factor=0.5, status_forcelist=[429, 500, 502, 503, 504])
adapter = HTTPAdapter(max_retries=retries)
session.mount('https://', adapter)
session.mount('http://', adapter)
try:
response = session.get('https://httpbin.org/status/429')
print(response.status_code)
except requests.exceptions.RetryError as e:
print('Исчерпаны попытки:', e)После 3 попыток с задержкой будет выброшено исключение RetryError
Пример 4: Асинхронные запросы с aiohttp и обработка ошибок
import aiohttp
import asyncio
async def fetch_with_retry(session, url, retries=3):
for attempt in range(retries):
try:
async with session.get(url, timeout=aiohttp.ClientTimeout(total=10)) as resp:
if resp.status == 200:
return await resp.json()
else:
print(f'Попытка {attempt+1}: статус {resp.status}')
except (aiohttp.ClientError, asyncio.TimeoutError) as e:
print(f'Попытка {attempt+1}: ошибка {e}')
await asyncio.sleep(0.5 * (attempt + 1))
return None
async def main():
urls = ['https://api.github.com/users/octocat', 'https://httpbin.org/delay/5']
async with aiohttp.ClientSession() as session:
tasks = [fetch_with_retry(session, url) for url in urls]
results = await asyncio.gather(*tasks)
for r in results:
if r:
print(r.get('login') or r)
asyncio.run(main())octocat None (из-за таймаута) или данные из /delay/5 при успехе
Пример 5: Использование urllib с OAuth2 авторизацией (код без библиотек)
from urllib.request import Request, urlopen
from urllib.parse import urlencode
# Предположим, у нас есть токен доступа
token = 'your_access_token'
headers = {'Authorization': f'Bearer {token}'}
req = Request('https://api.example.com/data', headers=headers, method='GET')
with urlopen(req) as resp:
data = resp.read()
print(data.decode()[:200])Ответ в JSON формате (если сервер поддерживает)
При использовании urllib необходимо вручную обрабатывать кодировку и ошибки HTTP, что увеличивает объем кода.