Как выполнить URL-кодирование в Python (полное руководство по urllib.parse)
URL-кодирование в Python выполняется с помощью urllib.parse.quote() для percent-кодирования строк и urllib.parse.urlencode() для кодирования словарей в строки запроса. В этом руководстве разбираются quote(), unquote(), urlencode() и parse_qs() на практических примерах.
URL-кодирование с помощью quote()
Функция urllib.parse.quote() — это основной инструмент Python для percent-кодирования строк. Она преобразует символы, небезопасные для использования в URL, в их percent-кодированные эквиваленты. По умолчанию прямые слэши (/) считаются безопасными символами, но это поведение можно настроить.
from urllib.parse import quote
# Базовое кодирование
print(quote('hello world'))
# Вывод: hello%20world
# Кодирование специальных символов
print(quote('price=10&qty=2'))
# Вывод: price%3D10%26qty%3D2
# По умолчанию / не кодируется
print(quote('path/to/file'))
# Вывод: path/to/file
# Чтобы закодировать и слэши, задайте safe=''
print(quote('path/to/file', safe=''))
# Вывод: path%2Fto%2Ffile
# Кодирование Unicode-символов
print(quote('cafe'))
# Вывод: caf%C3%A9
# Указание дополнительных безопасных символов
print(quote('key=value&foo=bar', safe='=&'))
# Вывод: key=value&foo=bar
Параметр safe — это ключ к управлению тем, что именно кодируется. По умолчанию safe='/'. Если нужно закодировать всё, кроме буквенно-цифровых символов и _.-~, задайте safe=''. Это эквивалентно функции encodeURIComponent() в JavaScript.
Существует также функция quote_plus(), которая работает как quote(), но кодирует пробелы как + вместо %20. Именно этот формат используется в данных HTML-форм (application/x-www-form-urlencoded).
from urllib.parse import quote_plus
print(quote_plus('hello world'))
# Вывод: hello+world
print(quote_plus('key=value&name=John Doe'))
# Вывод: key%3Dvalue%26name%3DJohn+Doe
URL-декодирование с помощью unquote()
Функция urllib.parse.unquote() выполняет обратное percent-кодирование, преобразуя последовательности %XX обратно в исходные символы. Существует также функция unquote_plus(), которая дополнительно преобразует знаки + в пробелы.
from urllib.parse import unquote, unquote_plus
# Базовое декодирование
print(unquote('hello%20world'))
# Вывод: hello world
print(unquote('caf%C3%A9'))
# Вывод: cafe (с диакритическим знаком)
# unquote НЕ преобразует + в пробел
print(unquote('hello+world'))
# Вывод: hello+world
# unquote_plus преобразует + в пробел
print(unquote_plus('hello+world'))
# Вывод: hello world
# Декодирование полного URL
url = 'https://example.com/search?q=C%2B%2B%20programming'
print(unquote(url))
# Вывод: https://example.com/search?q=C++ programming
Всегда используйте unquote_plus() при декодировании данных форм, поскольку HTML-формы кодируют пробелы как +. Используйте unquote() для общего URL-декодирования, где пробелы закодированы как %20.
Кодирование строк запроса с помощью urlencode()
Функция urllib.parse.urlencode() принимает словарь или список кортежей и преобразует их в правильно отформатированную строку запроса. Это наиболее удобный способ построения строк запроса в Python.
from urllib.parse import urlencode
# Словарь в строку запроса
params = {
'q': 'python programming',
'page': 1,
'lang': 'en'
}
print(urlencode(params))
# Вывод: q=python+programming&page=1&lang=en
# Список кортежей (сохраняет порядок, допускает повторяющиеся ключи)
params = [
('tag', 'python'),
('tag', 'web'),
('sort', 'date')
]
print(urlencode(params))
# Вывод: tag=python&tag=web&sort=date
# Использование doseq=True для значений-списков
params = {
'tag': ['python', 'web', 'api'],
'sort': 'date'
}
print(urlencode(params, doseq=True))
# Вывод: tag=python&tag=web&tag=api&sort=date
# Использование quote_via для управления кодированием пробелов
from urllib.parse import quote
params = {'q': 'hello world'}
print(urlencode(params, quote_via=quote))
# Вывод: q=hello%20world (использует %20 вместо +)
По умолчанию urlencode() внутренне использует quote_plus(), а значит пробелы становятся +. Если для пробелов нужен %20, передайте quote_via=quote, как показано выше.
Разбор строк запроса с помощью parse_qs()
Функция urllib.parse.parse_qs() разбирает строку запроса обратно в словарь. Каждое значение в словаре представляет собой список, поскольку параметры запроса могут иметь несколько значений. Существует также функция parse_qsl(), которая возвращает список кортежей.
from urllib.parse import parse_qs, parse_qsl
# Разбор строки запроса в словарь
qs = 'q=python+programming&page=1&lang=en'
result = parse_qs(qs)
print(result)
# Вывод: {'q': ['python programming'], 'page': ['1'], 'lang': ['en']}
# Примечание: значения всегда являются списками
print(result['q'][0]) # 'python programming'
# Обработка нескольких значений для одного ключа
qs = 'tag=python&tag=web&tag=api'
result = parse_qs(qs)
print(result)
# Вывод: {'tag': ['python', 'web', 'api']}
# parse_qsl возвращает список кортежей
result = parse_qsl(qs)
print(result)
# Вывод: [('tag', 'python'), ('tag', 'web'), ('tag', 'api')]
# Сохранение пустых значений (по умолчанию они опускаются)
qs = 'name=John&email=&age=30'
print(parse_qs(qs, keep_blank_values=True))
# Вывод: {'name': ['John'], 'email': [''], 'age': ['30']}
Кодирование полных URL с помощью urlparse
При работе с полными URL функции Python urlparse() и urlunparse() позволяют безопасно разбирать и заново собирать URL. Это особенно полезно, когда нужно изменить отдельные части URL, не нарушая его структуру.
from urllib.parse import urlparse, urlunparse, urlencode, quote
# Разбор URL на компоненты
url = 'https://example.com/search?q=hello&page=1#results'
parsed = urlparse(url)
print(parsed.scheme) # 'https'
print(parsed.netloc) # 'example.com'
print(parsed.path) # '/search'
print(parsed.query) # 'q=hello&page=1'
print(parsed.fragment) # 'results'
# Построение URL из компонентов
from urllib.parse import ParseResult
new_url = urlunparse(ParseResult(
scheme='https',
netloc='api.example.com',
path='/v2/search',
params='',
query=urlencode({'q': 'python & java', 'limit': 10}),
fragment=''
))
print(new_url)
# Вывод: https://api.example.com/v2/search?q=python+%26+java&limit=10
# Безопасное добавление сегмента пути со специальными символами
base = 'https://example.com/files/'
filename = 'my report (final).pdf'
safe_url = base + quote(filename, safe='')
print(safe_url)
# Вывод: https://example.com/files/my%20report%20%28final%29.pdf
Для современного кода на Python стоит рассмотреть библиотеку requests, которая автоматически выполняет URL-кодирование, когда вы передаёте параметры в виде словаря. Библиотека httpx также предоставляет аналогичные возможности автоматического кодирования.
import requests
# requests выполняет кодирование автоматически
response = requests.get(
'https://api.example.com/search',
params={
'q': 'python & java',
'page': 1,
'sort': 'relevance'
}
)
print(response.url)
# https://api.example.com/search?q=python+%26+java&page=1&sort=relevance