Python9 min di lettura

Come fare l'URL encoding in Python (guida completa a urllib.parse)

In Python l'URL encoding si effettua con urllib.parse.quote() per il percent-encoding delle stringhe e con urllib.parse.urlencode() per codificare i dizionari in query string. Questa guida illustra quote(), unquote(), urlencode() e parse_qs() con esempi pratici.

URL encoding con quote()

La funzione urllib.parse.quote() è lo strumento principale di Python per il percent-encoding delle stringhe. Converte i caratteri non sicuri per l'uso negli URL nei loro equivalenti percent-encoded. Per impostazione predefinita considera le barre (/) come caratteri sicuri, ma è possibile personalizzare questo comportamento.

from urllib.parse import quote

# Codifica di base
print(quote('hello world'))
# Output: hello%20world

# Codifica dei caratteri speciali
print(quote('price=10&qty=2'))
# Output: price%3D10%26qty%3D2

# Per impostazione predefinita, / non viene codificato
print(quote('path/to/file'))
# Output: path/to/file

# Per codificare anche le barre, imposta safe=''
print(quote('path/to/file', safe=''))
# Output: path%2Fto%2Ffile

# Codifica dei caratteri Unicode
print(quote('cafe'))
# Output: caf%C3%A9

# Specifica di caratteri sicuri aggiuntivi
print(quote('key=value&foo=bar', safe='=&'))
# Output: key=value&foo=bar

Il parametro safe è la chiave per controllare ciò che viene codificato. Per impostazione predefinita, safe='/'. Se vuoi codificare tutto tranne i caratteri alfanumerici e _.-~, imposta safe=''. Questo equivale alla funzione encodeURIComponent() di JavaScript.

Esiste anche quote_plus(), che funziona come quote() ma codifica gli spazi come + invece di %20. Questo è il formato usato nei dati dei form HTML (application/x-www-form-urlencoded).

from urllib.parse import quote_plus

print(quote_plus('hello world'))
# Output: hello+world

print(quote_plus('key=value&name=John Doe'))
# Output: key%3Dvalue%26name%3DJohn+Doe

URL decoding con unquote()

La funzione urllib.parse.unquote() inverte il percent-encoding, riconvertendo le sequenze %XX nei caratteri originali. Esiste anche unquote_plus(), che in aggiunta converte i segni + in spazi.

from urllib.parse import unquote, unquote_plus

# Decodifica di base
print(unquote('hello%20world'))
# Output: hello world

print(unquote('caf%C3%A9'))
# Output: cafe (con accento)

# unquote NON converte + in spazio
print(unquote('hello+world'))
# Output: hello+world

# unquote_plus converte + in spazio
print(unquote_plus('hello+world'))
# Output: hello world

# Decodifica di un URL completo
url = 'https://example.com/search?q=C%2B%2B%20programming'
print(unquote(url))
# Output: https://example.com/search?q=C++ programming

Usa sempre unquote_plus() quando decodifichi i dati di un form, poiché i form HTML codificano gli spazi come +. Usa unquote() per la decodifica generica degli URL, dove gli spazi sono codificati come %20.

Codifica delle query string con urlencode()

La funzione urllib.parse.urlencode() accetta un dizionario o una lista di tuple e la converte in una query string correttamente formattata. È il modo più comodo per costruire query string in Python.

from urllib.parse import urlencode

# Da dizionario a query string
params = {
    'q': 'python programming',
    'page': 1,
    'lang': 'en'
}
print(urlencode(params))
# Output: q=python+programming&page=1&lang=en

# Lista di tuple (conserva l'ordine, consente chiavi duplicate)
params = [
    ('tag', 'python'),
    ('tag', 'web'),
    ('sort', 'date')
]
print(urlencode(params))
# Output: tag=python&tag=web&sort=date

# Uso di doseq=True per valori di tipo lista
params = {
    'tag': ['python', 'web', 'api'],
    'sort': 'date'
}
print(urlencode(params, doseq=True))
# Output: tag=python&tag=web&tag=api&sort=date

# Uso di quote_via per controllare la codifica degli spazi
from urllib.parse import quote
params = {'q': 'hello world'}
print(urlencode(params, quote_via=quote))
# Output: q=hello%20world  (usa %20 invece di +)

Per impostazione predefinita, urlencode() usa internamente quote_plus(), il che significa che gli spazi diventano +. Se hai bisogno di %20 per gli spazi, passa quote_via=quote come mostrato sopra.

Parsing delle query string con parse_qs()

La funzione urllib.parse.parse_qs() esegue il parsing di una query string riconvertendola in un dizionario. Ogni valore del dizionario è una lista, poiché i parametri di query possono avere più valori. Esiste anche parse_qsl(), che restituisce una lista di tuple.

from urllib.parse import parse_qs, parse_qsl

# Parsing di una query string in un dizionario
qs = 'q=python+programming&page=1&lang=en'
result = parse_qs(qs)
print(result)
# Output: {'q': ['python programming'], 'page': ['1'], 'lang': ['en']}

# Nota: i valori sono sempre liste
print(result['q'][0])  # 'python programming'

# Gestione di più valori per la stessa chiave
qs = 'tag=python&tag=web&tag=api'
result = parse_qs(qs)
print(result)
# Output: {'tag': ['python', 'web', 'api']}

# parse_qsl restituisce una lista di tuple
result = parse_qsl(qs)
print(result)
# Output: [('tag', 'python'), ('tag', 'web'), ('tag', 'api')]

# Mantieni i valori vuoti (per impostazione predefinita vengono omessi)
qs = 'name=John&email=&age=30'
print(parse_qs(qs, keep_blank_values=True))
# Output: {'name': ['John'], 'email': [''], 'age': ['30']}

Codifica di URL completi con urlparse

Quando si lavora con URL completi, le funzioni urlparse() e urlunparse() di Python permettono di scomporre e ricostruire gli URL in modo sicuro. Questo è particolarmente utile quando è necessario modificare parti specifiche di un URL senza comprometterne la struttura.

from urllib.parse import urlparse, urlunparse, urlencode, quote

# Parsing di un URL nei suoi componenti
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'

# Costruzione di un URL dai suoi componenti
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)
# Output: https://api.example.com/v2/search?q=python+%26+java&limit=10

# Aggiunta sicura di un segmento di percorso con caratteri speciali
base = 'https://example.com/files/'
filename = 'my report (final).pdf'
safe_url = base + quote(filename, safe='')
print(safe_url)
# Output: https://example.com/files/my%20report%20%28final%29.pdf

Per il codice Python moderno, valuta l'uso della libreria requests, che gestisce automaticamente l'URL encoding quando passi i parametri come dizionario. Anche la libreria httpx offre analoghe funzionalità di codifica automatica.

import requests

# requests gestisce la codifica 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

Articoli correlati

Prova i nostri strumenti gratuiti