Como Codificar URLs em Python (Guia Completo do urllib.parse)
A codificacao de URLs em Python usa urllib.parse.quote() para fazer o percent-encoding de strings e urllib.parse.urlencode() para codificar dicionarios em query strings. Este guia aborda quote(), unquote(), urlencode() e parse_qs() com exemplos praticos.
Codificacao de URLs com quote()
A funcao urllib.parse.quote() e a principal ferramenta do Python para fazer o percent-encoding de strings. Ela converte caracteres que nao sao seguros para uso em URLs em seus equivalentes com percent-encoding. Por padrao, ela considera as barras (/) como caracteres seguros, mas voce pode personalizar esse comportamento.
from urllib.parse import quote
# Codificacao basica
print(quote('hello world'))
# Saida: hello%20world
# Codificando caracteres especiais
print(quote('price=10&qty=2'))
# Saida: price%3D10%26qty%3D2
# Por padrao, / nao e codificada
print(quote('path/to/file'))
# Saida: path/to/file
# Para codificar as barras tambem, use safe=''
print(quote('path/to/file', safe=''))
# Saida: path%2Fto%2Ffile
# Codificando caracteres Unicode
print(quote('cafe'))
# Saida: caf%C3%A9
# Especificando caracteres seguros adicionais
print(quote('key=value&foo=bar', safe='=&'))
# Saida: key=value&foo=bar
O parametro safe e a chave para controlar o que sera codificado. Por padrao, safe='/'. Se voce quiser codificar tudo, exceto caracteres alfanumericos e _.-~, use safe=''. Isso e equivalente ao encodeURIComponent() do JavaScript.
Existe tambem quote_plus(), que funciona como quote(), mas codifica espacos como + em vez de %20. Esse e o formato usado nos dados de formularios HTML (application/x-www-form-urlencoded).
from urllib.parse import quote_plus
print(quote_plus('hello world'))
# Saida: hello+world
print(quote_plus('key=value&name=John Doe'))
# Saida: key%3Dvalue%26name%3DJohn+Doe
Decodificacao de URLs com unquote()
A funcao urllib.parse.unquote() reverte o percent-encoding, convertendo sequencias %XX de volta aos seus caracteres originais. Existe tambem unquote_plus(), que adicionalmente converte sinais de + em espacos.
from urllib.parse import unquote, unquote_plus
# Decodificacao basica
print(unquote('hello%20world'))
# Saida: hello world
print(unquote('caf%C3%A9'))
# Saida: cafe (com acento)
# unquote NAO converte + em espaco
print(unquote('hello+world'))
# Saida: hello+world
# unquote_plus converte + em espaco
print(unquote_plus('hello+world'))
# Saida: hello world
# Decodificando uma URL completa
url = 'https://example.com/search?q=C%2B%2B%20programming'
print(unquote(url))
# Saida: https://example.com/search?q=C++ programming
Use sempre unquote_plus() ao decodificar dados de formularios, ja que os formularios HTML codificam espacos como +. Use unquote() para a decodificacao geral de URLs, em que os espacos sao codificados como %20.
Codificando Query Strings com urlencode()
A funcao urllib.parse.urlencode() recebe um dicionario ou uma lista de tuplas e o converte em uma query string devidamente formatada. Essa e a maneira mais conveniente de construir query strings em Python.
from urllib.parse import urlencode
# Dicionario para query string
params = {
'q': 'python programming',
'page': 1,
'lang': 'en'
}
print(urlencode(params))
# Saida: q=python+programming&page=1&lang=en
# Lista de tuplas (preserva a ordem, permite chaves duplicadas)
params = [
('tag', 'python'),
('tag', 'web'),
('sort', 'date')
]
print(urlencode(params))
# Saida: tag=python&tag=web&sort=date
# Usando doseq=True para valores em lista
params = {
'tag': ['python', 'web', 'api'],
'sort': 'date'
}
print(urlencode(params, doseq=True))
# Saida: tag=python&tag=web&tag=api&sort=date
# Usando quote_via para controlar a codificacao de espacos
from urllib.parse import quote
params = {'q': 'hello world'}
print(urlencode(params, quote_via=quote))
# Saida: q=hello%20world (usa %20 em vez de +)
Por padrao, urlencode() usa quote_plus() internamente, o que significa que os espacos se tornam +. Se voce precisar de %20 para os espacos, passe quote_via=quote, como mostrado acima.
Analisando Query Strings com parse_qs()
A funcao urllib.parse.parse_qs() analisa uma query string de volta para um dicionario. Cada valor no dicionario e uma lista, ja que os parametros de consulta podem ter varios valores. Existe tambem parse_qsl(), que retorna uma lista de tuplas.
from urllib.parse import parse_qs, parse_qsl
# Analisa uma query string em um dicionario
qs = 'q=python+programming&page=1&lang=en'
result = parse_qs(qs)
print(result)
# Saida: {'q': ['python programming'], 'page': ['1'], 'lang': ['en']}
# Observacao: os valores sao sempre listas
print(result['q'][0]) # 'python programming'
# Tratando multiplos valores para a mesma chave
qs = 'tag=python&tag=web&tag=api'
result = parse_qs(qs)
print(result)
# Saida: {'tag': ['python', 'web', 'api']}
# parse_qsl retorna uma lista de tuplas
result = parse_qsl(qs)
print(result)
# Saida: [('tag', 'python'), ('tag', 'web'), ('tag', 'api')]
# Manter valores em branco (por padrao eles sao omitidos)
qs = 'name=John&email=&age=30'
print(parse_qs(qs, keep_blank_values=True))
# Saida: {'name': ['John'], 'email': [''], 'age': ['30']}
Codificando URLs Completas com urlparse
Ao trabalhar com URLs completas, as funcoes urlparse() e urlunparse() do Python permitem decompor e reconstruir URLs com seguranca. Isso e especialmente util quando voce precisa modificar partes especificas de uma URL sem quebrar sua estrutura.
from urllib.parse import urlparse, urlunparse, urlencode, quote
# Analisa uma URL em componentes
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'
# Constroi uma URL a partir dos componentes
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)
# Saida: https://api.example.com/v2/search?q=python+%26+java&limit=10
# Adiciona com seguranca um segmento de caminho com caracteres especiais
base = 'https://example.com/files/'
filename = 'my report (final).pdf'
safe_url = base + quote(filename, safe='')
print(safe_url)
# Saida: https://example.com/files/my%20report%20%28final%29.pdf
Para codigo Python moderno, considere usar a biblioteca requests, que trata a codificacao de URLs automaticamente quando voce passa os parametros como um dicionario. A biblioteca httpx tambem oferece recursos de codificacao automatica semelhantes.
import requests
# requests trata a codificacao automaticamente
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