Библиотека requests: первые запросы
requests — самая популярная Python-библиотека для отправки HTTP-запросов.
requests превращает HTTP в одну строку кода: requests.get(url) возвращает объект ответа с кодом статуса, заголовками и телом страницы.Стандартная библиотека Python умеет ходить в сеть через urllib, но делать это вручную неудобно. Библиотека requests стала де-факто стандартом: простой синтаксис, автоматические редиректы, удобная работа с куки и заголовками. Это первый инструмент, который скрейпер ставит в проект.
Важно: requests — внешняя библиотека, её нет в браузерном Pyodide. Поэтому код с requests в этом курсе показан как пример для запуска у тебя на компьютере, а не в нашем онлайн-раннере. Сначала установим:
pip install requestsБазовый GET-запрос выглядит так:
import requests
resp = requests.get('https://example.com')
print(resp.status_code) # 200
print(resp.headers['Content-Type'])
print(resp.text[:200]) # первые 200 символов HTMLЗаголовки, параметры и таймауты
Чтобы выглядеть как обычный браузер и не получить 403, скрейперу часто нужно передать заголовки — прежде всего User-Agent. Параметры запроса удобно передавать словарём — requests сам соберёт query-string.
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (обучающий скрейпер; +https://my-site/bot)'
}
params = {'page': 2, 'sort': 'price'}
resp = requests.get(
'https://shop.example/catalog',
headers=headers,
params=params,
timeout=10, # не ждать ответа вечно
)
resp.raise_for_status() # бросит исключение на 4xx/5xx
print(resp.url) # итоговый URL с параметрамиКак работает под капотом
Под капотом requests открывает TCP-соединение, отправляет правильно оформленные HTTP-заголовки, читает ответ и оборачивает его в удобный объект Response. Свойство .text — это тело, декодированное в строку; .content — сырые байты (нужны для картинок); .json() — разбор тела как JSON, если сервер вернул API-ответ. Метод raise_for_status() превращает «плохие» коды (4xx/5xx) в исключения, чтобы ошибка не прошла незамеченной.
Сессии, куки и повторные попытки
Когда запросов к одному сайту много, отдельные requests.get неэффективны: на каждый заново устанавливается соединение. Объект requests.Session() переиспользует TCP-соединение и автоматически хранит куки между запросами — это и быстрее, и ближе к поведению браузера. Через сессию удобно один раз задать общие заголовки (session.headers.update(...)), и они применятся ко всем последующим запросам.
Сеть ненадёжна: соединение может оборваться, сервер — временно ответить 503. Промышленный скрейпер не падает от первой же ошибки, а повторяет запрос с нарастающей паузой — это называется экспоненциальный бэк-офф: подождать 1 секунду, затем 2, затем 4. Такой подход одновременно устойчив к сбоям и вежлив: получив 429 или 503, ты не продолжаешь долбить сервер, а даёшь ему передышку. Эту логику можно написать руками или взять готовый адаптер HTTPAdapter с настройкой Retry.
Частые ошибки
- Запрос без таймаута. Без
timeoutскрипт может зависнуть навсегда на медленном сервере. - Игнорировать кодировку. Иногда
resp.encodingопределяется неверно — кириллица превращается в кракозябры; задай кодировку явно. - Не переиспользовать сессию. Для множества запросов к одному сайту лучше
requests.Session()— она держит соединение и куки.
Best practices
- Всегда указывай
timeoutи проверяй статус (raise_for_status()). - Используй
Session()для серии запросов — это быстрее и сохраняет куки. - Передавай осмысленный
User-Agentс контактом — это честно по отношению к сайту.
Не забывай про кодировку ответа. Иногда сервер не указывает её корректно, и requests неверно угадывает — кириллица превращается в нечитаемые символы. В таких случаях кодировку задают явно (resp.encoding = 'utf-8') до обращения к resp.text, либо работают с сырыми байтами resp.content и декодируют сами. Этот нюанс особенно часто всплывает на старых русскоязычных сайтах. Понимание разницы между .text (декодированная строка) и .content (байты) избавляет от целого класса загадочных «кракозябр» в собранных данных.
Полезно с самого начала логировать ход работы: какой URL запрашиваем, какой код вернулся, сколько данных извлекли. Модуль logging из стандартной библиотеки подходит идеально и не требует зависимостей. Логи бесценны, когда скрейпер падает на тысячной странице из десяти тысяч: по записям видно, на каком URL и с каким кодом ответа что-то пошло не так. Привычка логировать, а не печатать print наугад, отличает одноразовый скрипт от инструмента, которому можно доверить регулярный сбор данных.
Итог: requests — рабочая лошадка скрейпинга для статических страниц. Запомни связку get → status → text, всегда ставь таймаут и проверяй код ответа.