Параметры HTTP запроса в Python: от базовых до продвинутых техник
Основные способы передачи параметров HTTP запроса
Параметры HTTP запроса (query string parameters) используются для передачи данных на сервер через URL. В Python существует несколько подходов для их формирования и отправки. Наиболее удобным и распространённым является использование библиотеки requests, которая автоматически кодирует параметры и обрабатывает специальные символы.
Библиотека requests: параметр params
Этот способ считается наиболее эффективным для синхронных запросов. Параметры передаются в виде словаря, и библиотека сама формирует корректную строку запроса, кодируя пробелы, кириллицу и другие символы.
import requests
params = {
'search': 'Python HTTP',
'page': 1,
'limit': 10
}
response = requests.get('https://api.example.com/items', params=params)
print(response.url)параметры запроса python (параметры http запроса в python)
https://api.example.com/items?search=Python+HTTP&page=1&limit=10
Пояснение: Ключи и значения автоматически экранируются (пробел заменяется на +). Можно передавать списки значений, используя список в качестве значения:
params = {'tag': ['python', 'http']}
response = requests.get('https://api.example.com/items', params=params)
print(response.url)
https://api.example.com/items?tag=python&tag=http
Типичная ошибка: Если передать в параметрах значения None, requests не включит их в URL. Иногда это неожиданно, если нужно явно передать пустой параметр. Решение - использовать пустую строку вместо None.
Проблема с неверным типом: если ключи или значения не строки, requests преобразует их через str(). Для булевых значений стоит явно приводить к строке, если требуется 'true'/'false'.
Как передать параметры без сторонних библиотек?
Используется встроенная библиотека urllib и функция urlencode из модуля urllib.parse. Этот вариант подходит, когда нельзя устанавливать внешние пакеты.
from urllib.parse import urlencode
from urllib.request import urlopen
params = {'q': 'python requests', 'page': 2}
query_string = urlencode(params)
url = 'https://api.example.com/search?' + query_string
with urlopen(url) as response:
print(response.read().decode())
Пояснение: urlencode кодирует словарь в строку запроса. Результат можно объединить с базовым URL. Для добавления нескольких одинаковых ключей (например, tag=python&tag=http) следует передать список кортежей:
params = [('tag', 'python'), ('tag', 'http')]
query_string = urlencode(params)
print(query_string)
tag=python&tag=http
Проблема: urlencode по умолчанию кодирует пробел как '+', что соответствует application/x-www-form-urlencoded, но не всем серверам это подходит. Для использования %20 требуется параметр quote_via. Также необходимо самостоятельно обрабатывать исключения при сетевых ошибках.
Как работать с асинхронными запросами и параметрами?
Современная библиотека httpx поддерживает как синхронный, так и асинхронный режимы, а также HTTP/2. Параметры задаются аналогично requests.
import httpx
params = {'country': 'Россия', 'lang': 'ru'}
# Синхронный режим
response = httpx.get('https://api.example.com/locations', params=params)
print(response.url)
# Асинхронный режим
import asyncio
async def fetch():
async with httpx.AsyncClient() as client:
resp = await client.get('https://api.example.com/locations', params=params)
return resp.url
url = asyncio.run(fetch())
print(url)
Ошибка: При передаче параметров в асинхронном клиенте легко забыть про await. Также httpx требует обработки исключений типа httpx.RequestError. Для кириллицы кодирование работает корректно, но если параметры уже содержат символы '=' или '&', они экранируются.
Как отправлять асинхронные запросы с параметрами в aiohttp?
aiohttp - популярная асинхронная библиотека. Параметры передаются через аргумент params.
import aiohttp
import asyncio
async def fetch():
params = {'id': [1, 2, 3], 'sort': 'desc'}
async with aiohttp.ClientSession() as session:
async with session.get('https://api.example.com/data', params=params) as resp:
print(resp.url)
asyncio.run(fetch())
https://api.example.com/data?id=1&id=2&id=3&sort=desc
Проблема: aiohttp не поддерживает параметр params для POST-запросов с телом формы; для этого используется data. Также если нужно передать параметры во вложенном виде (например, filter[name]=xxx), aiohttp не делает этого автоматически - требуется ручное формирование строки запроса.
Как вручную собрать URL с параметрами для простых случаев?
Когда параметры заранее известны и не содержат специальных символов, можно использовать f-строки или конкатенацию. Этот метод не рекомендуется для production из-за риска некорректного кодирования.
base_url = 'https://api.example.com/items'
params = {'page': '1', 'limit': '20'}
query = '&'.join(f'{k}={v}' for k, v in params.items())
url = base_url + '?' + query
print(url)
https://api.example.com/items?page=1&limit=20
Проблема: Если значения содержат пробелы, кириллицу, символы & или =, строка будет некорректной. Необходимо экранировать вручную через urllib.parse.quote. Также невозможно передать несколько значений с одинаковым ключом без дублирования кода.
Расширенные примеры работы с параметрами
В этом разделе рассматриваются нестандартные сценарии, которые часто встречаются при интеграции с веб-API.
Вложенные параметры (nested query strings)
Некоторые API ожидают параметры вида filter[name]=value. Ни одна из стандартных библиотек не поддерживает это автоматически, поэтому требуется ручное формирование.
from urllib.parse import urlencode
def nested_params(params, prefix=''):
items = []
for key, value in params.items():
full_key = f'{prefix}[{key}]' if prefix else key
if isinstance(value, dict):
items.extend(nested_params(value, full_key).items())
else:
items.append((full_key, value))
return dict(items)
params = {
'filter': {'name': 'John', 'age': 30},
'sort': 'name'
}
flat = nested_params(params)
query = urlencode(flat)
print(query)
filter%5Bname%5D=John&filter%5Bage%5D=30&sort=name
Пояснение: Рекурсивно строятся ключи с квадратными скобками. После декодирования %5B - это '[' , %5D - ']'.
Передача списков с разными стилями
Некоторые API поддерживают индексированные списки: filter[0][name]=aaa. Пример построения такой строки:
from urllib.parse import urlencode
items = [{'name': 'Alice'}, {'name': 'Bob'}]
params = []
for i, item in enumerate(items):
for k, v in item.items():
params.append((f'filter[{i}][{k}]', v))
query = urlencode(params)
print(query)
filter%5B0%5D%5Bname%5D=Alice&filter%5B1%5D%5Bname%5D=Bob
Комбинирование параметров с телом POST запроса
Иногда в одном запросе нужно отправить query-параметры в URL и данные формы в теле. Библиотека requests это позволяет:
import requests
params = {'api_key': '12345'}
data = {'username': 'user', 'password': 'pass'}
response = requests.post('https://example.com/login', params=params, data=data)
print('URL:', response.request.url)
print('Body:', response.request.body)
URL: https://example.com/login?api_key=12345 Body: username=user&password=pass
Обработка кириллицы и спецсимволов в параметрах
При работе с русскими текстами важно следить за кодировкой. Библиотека requests корректно обрабатывает UTF-8, но если сервер ожидает другую кодировку, можно задать параметр params в виде уже закодированных строк.
import requests
from urllib.parse import quote
# Ручное кодирование в cp1251
value = 'Москва'.encode('cp1251')
params = {'city': value}
# Неправильно: requests воспримет bytes как строку
response = requests.get('https://example.com', params=params)
print(response.url) # символы будут выглядеть как %XX
# Правильный способ: передать уже закодированную строку
params = {'city': quote('Москва', encoding='cp1251')}
response = requests.get('https://example.com', params=params)
print(response.url)
https://example.com?city=%CC%EE%F1%EA%E2%E0
Использование параметров с сессиями и куками
При создании сессии с помощью requests.Session() параметры передаются аналогично, но можно установить базовые параметры для всех запросов сессии.
import requests
session = requests.Session()
session.params = {'api_key': 'secret'}
# Теперь все GET запросы через сессию будут автоматически добавлять этот параметр
resp = session.get('https://api.example.com/items')
print(resp.url) # https://api.example.com/items?api_key=secret
Параметры для пагинации в REST API
Многие API используют параметры page и per_page или offset/limit. Пример цикла для сбора всех страниц:
import requests
base_url = 'https://api.example.com/users'
all_users = []
page = 1
per_page = 50
while True:
params = {'page': page, 'per_page': per_page}
response = requests.get(base_url, params=params)
data = response.json()
if not data: # пустой список
break
all_users.extend(data)
page += 1
print(f'Собрано {len(all_users)} пользователей')
В реальном API может быть ответ с полем `next` или `total_pages` - тогда логика строится на его основе.