Работа с заголовками запросов с помощью библиотеки requests
Основы установки заголовков
Как передать произвольные заголовки в запрос библиотеки requests?
Самый простой способ указать заголовки HTTP запроса в Python requests это передать словарь в параметр headers методов get, post, put и других. Пример:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'Accept': 'application/json'
}
response = requests.get('https://httpbin.org/headers', headers=headers)
print(response.json())
Python 2 requests (библиотека requests в python 2)
Пояснение: словарь headers содержит пары ключ-значение. Библиотека requests автоматически добавляет некоторые стандартные заголовки (например, Host), но пользовательские заголовки переопределяют значения по умолчанию. В ответе от httpbin мы увидим переданные заголовки.
Типичная ошибка: если заголовок содержит символы не ASCII (например, кириллица), requests может выбросить исключение UnicodeEncodeError. Для решения необходимо вручную кодировать значение, например, используя Header из email.utils или передавать байты. Также стоит избегать дублирования заголовков, requests использует последнее значение.
Как задать заголовки для всех запросов в рамках одной сессии?
Использование объекта Session позволяет установить заголовки один раз и применять их ко всем запросам, выполняемым через эту сессию. Это удобно для повторяющихся заголовков, например, авторизационного токена.
import requests
session = requests.Session()
session.headers.update({
'Authorization': 'Bearer YOUR_TOKEN',
'Accept': 'application/json'
})
response1 = session.get('https://api.example.com/users')
response2 = session.post('https://api.example.com/users', json={'name': 'John'})
Python 3 requests (библиотека requests в python 3)
Метод session.headers.update() добавляет или обновляет заголовки сессии. Заголовки, переданные непосредственно в запрос, имеют приоритет над заголовками сессии.
Важно: не путать метод update с присваиванием (session.headers = ...), который заменит все заголовки, включая внутренние. Рекомендуется использовать update.
Как подготовить запрос с заголовками, не отправляя его сразу?
Используя PreparedRequest, можно вручную собрать объект запроса, установить заголовки и затем отправить его через сессию. Это даёт полный контроль над формированием запроса.
from requests import Request, Session
url = 'https://httpbin.org/headers'
headers = {'X-Custom': 'value'}
req = Request('GET', url, headers=headers)
prepared = session.prepare_request(req)
# можно изменить prepared.headers перед отправкой
response = session.send(prepared)
Python requests url (выполнение запроса по url с помощью requests в python)
PreparedRequest позволяет также изменять заголовки после подготовки, если требуется динамическая корректировка.
Как передать базовую аутентификацию через заголовки вручную?
Можно вручную составить заголовок Authorization с использованием кодирования Base64. Однако requests предоставляет параметр auth, который делает это автоматически. Тем не менее, полезно знать ручной способ:
import requests
import base64
credentials = 'user:password'
encoded = base64.b64encode(credentials.encode()).decode()
headers = {'Authorization': f'Basic {encoded}'}
response = requests.get('https://httpbin.org/basic-auth/user/password', headers=headers)
Python requests headers (заголовки запросов в python requests)
Ошибка: неверное кодирование (пробелы, забыли декодировать из байтов) приводит к ошибке аутентификации.
Как передать cookies в заголовках запроса?
Хотя для cookies лучше использовать параметр cookies или объект CookieJar, можно передать их через заголовок Cookie напрямую:
headers = {'Cookie': 'session_id=abc123; theme=light'}
response = requests.get('https://httpbin.org/cookies', headers=headers)
Python requests exceptions (исключения в python requests)
Важно: если в заголовке Cookie и параметре cookies указаны одновременно, requests объединит их, но может возникнуть конфликт дублирования.
Как установить Content-Type для отправки данных?
При отправке JSON через параметр json requests автоматически устанавливает Content-Type: application/json. Однако если используется data, заголовок нужно задавать вручную:
import json
data = {'key': 'value'}
headers = {'Content-Type': 'application/json'}
response = requests.post('https://httpbin.org/post', data=json.dumps(data), headers=headers)
Распространённая ошибка: указать неверный Content-Type (например, application/x-www-form-urlencoded при отправке JSON) - сервер может неверно обработать данные.
Расширенные примеры работы с заголовками
Далее представлены более сложные и специализированные сценарии использования заголовков запросов.
Как имитировать браузер с помощью заголовков?
Современные веб-сайты часто проверяют User-Agent и Accept-Language. Без подходящих заголовков может возвращаться ошибка 403 или редирект на другую страницу. Пример:
import requests
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
'Accept-Language': 'ru-RU,ru;q=0.9,en;q=0.8',
'Accept-Encoding': 'gzip, deflate, br',
'Referer': 'https://www.google.com/'
}
response = requests.get('https://www.example.com', headers=headers)
print(response.status_code)
200
Пояснение: Заголовки User-Agent, Accept-Language, Referer помогают обойти базовую защиту от ботов. Однако для сложных систем может потребоваться работа с куками и JavaScript.
Как использовать заголовки для OAuth2 Bearer токена?
Большинство современных API требуют авторизацию через Bearer токен в заголовке Authorization. Пример:
import requests
from requests.exceptions import HTTPError
token = 'github_pat_...'
headers = {'Authorization': f'Bearer {token}'}
try:
response = requests.get('https://api.github.com/user', headers=headers)
response.raise_for_status()
print('Логин:', response.json()['login'])
except HTTPError as e:
if e.response.status_code == 401:
print('Токен недействителен')
else:
print(f'Ошибка: {e}')
Логин: username
При истечении токена сервер возвращает 401. Всегда обрабатывайте исключения для надёжности.
Как получить заголовки ответа сервера?
Объект response содержит атрибут headers, который является словарём всех заголовков ответа. Это полезно для проверки лимитов, типа контента или пользовательских заголовков.
response = requests.get('https://httpbin.org/response-headers?freeform=hello')
print(response.headers)
print('Тип контента:', response.headers.get('Content-Type'))
{'Date': 'Mon, 01 Jan 2024 12:00:00 GMT', 'Content-Type': 'application/json', 'freeform': 'hello', ...}
Тип контента: application/json
Обратите внимание: ключи заголовков регистронезависимы, requests использует CaseInsensitiveDict.
Как передать пользовательские идентификаторы в заголовках?
Часто для трассировки запросов используются заголовки X-Request-ID, X-Correlation-ID. Пример генерации уникального ID:
import uuid
headers = {
'X-Request-ID': str(uuid.uuid4()),
'X-Correlation-ID': 'my-app-correlation'
}
response = requests.post('https://httpbin.org/post', json={'data': 'test'}, headers=headers)
posted_headers = response.json()['headers']
print('X-Request-ID:', posted_headers.get('X-Request-ID'))
print('X-Correlation-ID:', posted_headers.get('X-Correlation-ID'))
X-Request-ID: 550e8400-e29b-41d4-a716-446655440000 X-Correlation-ID: my-app-correlation
Сервер может логировать эти ID для отладки.
Как управлять кэшированием через заголовки?
Заголовки Cache-Control, Expires, Pragma влияют на кэширование ответа. Пример запроса с требованием не кэшировать:
headers = {
'Cache-Control': 'no-cache, no-store, must-revalidate',
'Pragma': 'no-cache',
'Expires': '0'
}
response = requests.get('https://httpbin.org/cache', headers=headers)
print('Заголовки ответа:', response.headers.get('Cache-Control'))
Заголовки ответа: public, max-age=3600
Примечание: сервер может игнорировать эти заголовки.
Как обработать ошибку слишком длинного заголовка?
Серверы и промежуточные устройства имеют ограничения на размер заголовка (обычно 8-16 КБ). Если заголовок превышает лимит, возникает ошибка 400 Bad Request или соединение обрывается. Пример проблемы:
# Попытка отправить очень длинный заголовок
long_value = 'x' * 10000
headers = {'X-Long': long_value}
try:
response = requests.get('https://httpbin.org/headers', headers=headers, timeout=5)
print(response.status_code)
except requests.exceptions.RequestException as e:
print('Ошибка:', e)
400
Решение: уменьшить размер заголовка или использовать POST с телом запроса для больших данных.
Как сжать тело запроса с помощью заголовка Content-Encoding?
Можно отправить сжатые данные, указав Content-Encoding: gzip. Но это требует ручного сжатия тела. Пример:
import zlib, json
data = json.dumps({'key': 'value'}).encode()
compressed = zlib.compress(data)
headers = {
'Content-Type': 'application/json',
'Content-Encoding': 'deflate'
}
response = requests.post('https://httpbin.org/post', data=compressed, headers=headers)
print('Сервер получил данные:', response.json()['data'])
Сервер получил данные: {"key":"value"}
Внимание: не все серверы поддерживают приём сжатых данных. Обычно используется gzip, deflate или br.