Реальные скрипты для работы с API дают сбои. Сервер может вернуть 404, сеть может оборваться, запрос может превысить время ожидания. Явная обработка этих случаев делает скрипты надёжными.
Есть два типа сбоев:
1. **HTTP-ошибки** -- сервер отвечает, но с кодом ошибки (4xx или 5xx). По умолчанию `requests` не бросает исключение -- он возвращает ответ, и вызов `.json()` может вернуть payload ошибки вместо данных.
2. **Сетевые ошибки** -- запрос вообще не доходит до сервера или сервер не отвечает. Эти ошибки бросают исключения: ConnectionError, Timeout или базовый RequestException.
`raise_for_status()` устраняет пробел для HTTP-ошибок -- бросает HTTPError при статусе 4xx или 5xx:
```python
import requests
response = requests.get('https://apilearn.tukas.dev/api/products/99999/')
response.raise_for_status() # бросает HTTPError при 404
data = response.json() # выполняется только если статус 2xx
```
Для сетевых ошибок используйте try/except:
```python
try:
response = requests.get(url, timeout=5)
response.raise_for_status()
data = response.json()
except requests.exceptions.Timeout:
print('Запрос превысил время ожидания')
except requests.exceptions.ConnectionError:
print('Сетевая ошибка -- не удалось связаться с сервером')
except requests.exceptions.HTTPError as e:
print(f'HTTP ошибка: {e.response.status_code}')
```
Параметр `timeout=` устанавливает лимит времени в секундах. Без него зависший сервер может остановить скрипт навсегда:
```python
# Бросает Timeout если нет ответа в течение 5 секунд
response = requests.get(url, timeout=5)
# Отдельные таймауты для подключения и чтения
response = requests.get(url, timeout=(3, 10)) # (connect, read)
```
Иерархия исключений requests (от конкретных к общим):
```
RequestException Базовый класс для всех исключений requests
ConnectionError Не удалось связаться с сервером
ProxyError Ошибка подключения через прокси
Timeout Запрос превысил время ожидания
ConnectTimeout Таймаут подключения
ReadTimeout Таймаут чтения
HTTPError Статус 4xx или 5xx (raise_for_status)
TooManyRedirects Цикл перенаправлений
```
Перехват `RequestException` обрабатывает все типы сразу -- полезно для простых скриптов, где различие между типами ошибок не важно.
Сделайте GET к /api/products/99999/ (несуществующий продукт). Без raise_for_status() выведите код статуса. Затем добавьте raise_for_status() и обработайте исключение HTTPError, выведя сообщение об ошибке.
import requests
BASE_URL = 'https://apilearn.tukas.dev'
# Часть 1: без raise_for_status — проверьте код статуса
response = requests.get(f'{BASE_URL}/api/products/99999/')
print(response.status_code)
# Часть 2: с raise_for_status и обработкой HTTPError
Решение
import requests
BASE_URL = 'https://apilearn.tukas.dev'
# Часть 1: без raise_for_status
response = requests.get(f'{BASE_URL}/api/products/99999/')
print(response.status_code) # 404
# Часть 2: с raise_for_status
try:
response = requests.get(f'{BASE_URL}/api/products/99999/')
response.raise_for_status()
except requests.exceptions.HTTPError as e:
print(f'HTTP ошибка: {e.response.status_code}')
Попробуйте получить /api/users/profile/ БЕЗ заголовка авторизации. Обработайте HTTPError и выведите специальное сообщение, если статус 401.
import requests
BASE_URL = 'https://apilearn.tukas.dev'
# GET профиля без авторизации — обработайте 401 отдельно
try:
response = requests.get(f'{BASE_URL}/api/users/profile/')
response.raise_for_status()
except requests.exceptions.HTTPError as e:
# Выведите разные сообщения для 401 и других кодов
pass
Сделайте GET к /api/products/ с timeout=5. Обработайте Timeout и ConnectionError отдельно. Выведите список продуктов при успехе или сообщение об ошибке.
import requests
BASE_URL = 'https://apilearn.tukas.dev'
# GET с timeout и обработкой сетевых ошибок
Решение
import requests
BASE_URL = 'https://apilearn.tukas.dev'
try:
response = requests.get(f'{BASE_URL}/api/products/', timeout=5)
response.raise_for_status()
products = response.json()['results']
print(f'Получено {len(products)} продуктов')
except requests.exceptions.Timeout:
print('Ошибка: запрос превысил время ожидания')
except requests.exceptions.ConnectionError:
print('Ошибка: не удалось подключиться к API')
except requests.exceptions.HTTPError as e:
print(f'HTTP ошибка: {e.response.status_code}')
Напишите функцию safe_get(url, **kwargs), которая делает GET с timeout=5, вызывает raise_for_status() и возвращает JSON при успехе или None при любой ошибке (выводя сообщение). Протестируйте с валидным и несуществующим URL.
import requests
BASE_URL = 'https://apilearn.tukas.dev'
def safe_get(url, **kwargs):
# Реализуйте с timeout, raise_for_status и обработкой всех ошибок
pass
# Тест 1: валидный URL
result = safe_get(f'{BASE_URL}/api/products/')
if result:
print(f'Продуктов: {len(result["results"])}')
# Тест 2: несуществующий эндпоинт
result = safe_get(f'{BASE_URL}/api/products/99999/')
print(result)
Решение
import requests
BASE_URL = 'https://apilearn.tukas.dev'
def safe_get(url, **kwargs):
try:
response = requests.get(url, timeout=5, **kwargs)
response.raise_for_status()
return response.json()
except requests.exceptions.Timeout:
print(f'Ошибка: timeout при запросе к {url}')
except requests.exceptions.ConnectionError:
print(f'Ошибка: нет соединения с {url}')
except requests.exceptions.HTTPError as e:
print(f'HTTP {e.response.status_code} для {url}')
return None
result = safe_get(f'{BASE_URL}/api/products/')
if result:
print(f'Продуктов: {len(result["results"])}')
result = safe_get(f'{BASE_URL}/api/products/99999/')
print(result)
Напишите функцию retry_get(url, retries=3), которая повторяет запрос при кодах 429 или 503, ожидая 2**attempt секунд между попытками. При других ошибках — сразу бросать исключение. Выведите сообщение перед каждым ожиданием.
import requests
import time
BASE_URL = 'https://apilearn.tukas.dev'
def retry_get(url, retries=3, **kwargs):
# Повторяйте при 429/503, exponential backoff, бросайте при других ошибках
pass
# Тест с рабочим эндпоинтом (не активирует retry)
result = retry_get(f'{BASE_URL}/api/products/')
print(result['count'])
Решение
import requests
import time
BASE_URL = 'https://apilearn.tukas.dev'
def retry_get(url, retries=3, **kwargs):
for attempt in range(retries):
try:
response = requests.get(url, timeout=5, **kwargs)
response.raise_for_status()
return response.json()
except requests.exceptions.HTTPError as e:
if e.response.status_code in (429, 503) and attempt < retries - 1:
wait = 2 ** attempt
print(f'Попытка {attempt + 1} неудачна ({e.response.status_code}), ждём {wait}s...')
time.sleep(wait)
else:
raise
return None
result = retry_get(f'{BASE_URL}/api/products/')
print(result['count'])
No split tab
Настройки cookies
Мы используем необходимые cookies для работы сайта. С вашего разрешения мы также можем сохранять настройки сайта и использовать аналитические и рекламные cookies, чтобы понимать использование сайта и поддерживать развитие проекта.
* Вы всегда можете изменить свой выбор в настройках сайта.
Выберите категории cookies
Настройки аналитики
Можно отключить аналитику использования платформы. Также можно отправить в Google Analytics запрос на удаление данных об использовании этого сайта, связанных с этим браузером.
Учебный workspace
Учитесь, читая, запуская код и решая задачи.
Практикуйте программирование с пояснениями тем, упражнениями, инструментами browser IDE, проверкой regex и тренировкой печати кода в одном workspace.
Открывайте инструменты во вкладках.Упражнения, IDE-инструменты и тренажеры остаются доступными как вкладки сайта.
Переключайтесь без потери контекста.Переходите между пояснениями, кодом и утилитами, сохраняя свое место.
Используйте sidebar как карту.Левые панели содержат навигацию, настройки, файлы, libraries и управление инструментами.
PythonJavaScriptSQLite
Одна IDE, три практичных режима
Python в браузере.Запускайте небольшие скрипты, пробуйте библиотеки и тренируйте API-запросы без установки.
JavaScript для быстрых экспериментов.Проверяйте код для браузера и сравнивайте идеи рядом с учебными материалами.
SQLite для практики с данными.Открывайте обозреватель базы данных, изучайте таблицы, пишите запросы и учитесь SQL локально.
ТемаIDE
Работайте рядом в split tabs
Держите инструкции перед глазами.Откройте упражнение или справочную страницу рядом с IDE, вместо постоянных переключений.
Сравнивайте инструменты во время обучения.Размещайте проверки regex, пояснения и эксперименты с кодом рядом, когда это нужно для задачи.
Закройте split, когда закончите.Workspace вернётся к одной сфокусированной вкладке, а открытые вкладки сайта останутся доступны.
Тренажер слепой печати кода
Или просто текста
Тренажер рассчитан на физическую клавиатуру.Откройте этот раздел на ноутбуке или компьютере с широким экраном. На телефоне тренировка слепой печати не будет корректной.
Скорость: 0 зн/мин
0 слов/мин
Лучшая скорость (60с): 0 зн/мин
0 слов/мин
Ошибки: 0
Общее время: 0.0 с
Для активации режима слепого набора не подсматривайте на физическую клавиатуру.