Python9 min de leitura

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

Artigos relacionados

Experimente as nossas ferramentas gratuitas