¿Cómo codificar por ciento los parámetros de URL en Python?

299

Si lo hago

url = "http://example.com?p=" + urllib.quote(query)
  1. No codifica /a %2F(rompe la normalización de OAuth)
  2. No maneja Unicode (arroja una excepción)

¿Hay una mejor biblioteca?

Paul Tarjan
fuente
1
Estos no son parámetros de URL, para su información. Deberías aclararlo.
Jamie Marshall

Respuestas:

390

Python 2

De los documentos :

urllib.quote(string[, safe])

Reemplace los caracteres especiales en la cadena usando el escape% xx. Las letras, los dígitos y los caracteres '_.-' nunca se citan. De forma predeterminada, esta función está destinada a citar la sección de ruta de la URL. El parámetro seguro opcional especifica caracteres adicionales que no deben citarse; su valor predeterminado es '/'

Eso significa que pasar '' por seguro resolverá su primer problema:

>>> urllib.quote('/test')
'/test'
>>> urllib.quote('/test', safe='')
'%2Ftest'

Sobre el segundo problema, hay un informe de error al respecto aquí . Aparentemente se solucionó en Python 3. Puede solucionarlo codificando como utf8 de esta manera:

>>> query = urllib.quote(u"Müller".encode('utf8'))
>>> print urllib.unquote(query).decode('utf8')
Müller

Por cierto, eche un vistazo a urlencode

Python 3

Lo mismo, excepto reemplazar urllib.quotecon urllib.parse.quote.

Nadia Alramli
fuente
1
Gracias, ambos funcionaron muy bien. urlencode simplemente llama a quoteplus muchas veces en un bucle, que no es la normalización correcta para mi tarea (oauth).
Paul Tarjan
66
la especificación: rfc 2396 los define como reservados, reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" | "$" | ","que es lo que trata urllib.quote.
Jeff Sheffield
63
urllib.quotemovido a urlib.parse.quote, desde Python3.
Hibou57
55
urllib.parse.quote docs
Andreas Haferburg
Además, en el caso de codificar una consulta de búsqueda, quizás sea mejor usar quote_plus: docs.python.org/3/library/… 1. Codifica barras por defecto 2. También codifica espacios
Pavel Vergeev
174

En Python 3, urllib.quotese ha movido urllib.parse.quotey maneja unicode de manera predeterminada.

>>> from urllib.parse import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
>>> quote('/El Niño/')
'/El%20Ni%C3%B1o/'
Paolo Moretti
fuente
2
El nombre quotees bastante vago como global. Puede ser que sea más agradable de usar algo como urlencode: from urllib.parse import quote as urlencode.
Luc
Tenga en cuenta que hay una función llamada urlencodeen urllib.parseya que hace algo completamente diferente, por lo que sería mejor escoger otro nombre o el riesgo de confundir seriamente los futuros lectores de su código.
jaymmer - Restablece a Mónica el
48

Mi respuesta es similar a la respuesta de Paolo.

Creo que el módulo requestses mucho mejor. Se basa en urllib3. Puedes probar esto:

>>> from requests.utils import quote
>>> quote('/test')
'/test'
>>> quote('/test', safe='')
'%2Ftest'
Aminah Nuraini
fuente
55
requests.utils.quotees un enlace a python quote. Ver fuentes de solicitud .
Cjkjvfnby
16
requests.utils.quotees un envoltorio de compatibilidad delgado urllib.quotepara Python 2 y urllib.parse.quotePython 3
Jeff Sheffield
13

Si está usando django, puede usar urlquote:

>>> from django.utils.http import urlquote
>>> urlquote(u"Müller")
u'M%C3%BCller'

Tenga en cuenta que los cambios en Python desde que se publicó esta respuesta significa que ahora es un contenedor heredado. Del código fuente de Django 2.1 para django.utils.http:

A legacy compatibility wrapper to Python's urllib.parse.quote() function.
(was used for unicode handling on Python 2)
Rick Westera
fuente
2

Es mejor usar urlencodeaquí. No hay mucha diferencia para un solo parámetro, pero en mi humilde opinión, el código es más claro. (¡Parece confuso ver una función quote_plus! Especialmente las que provienen de otros idiomas)

In [21]: query='lskdfj/sdfkjdf/ksdfj skfj'

In [22]: val=34

In [23]: from urllib.parse import urlencode

In [24]: encoded = urlencode(dict(p=query,val=val))

In [25]: print(f"http://example.com?{encoded}")
http://example.com?p=lskdfj%2Fsdfkjdf%2Fksdfj+skfj&val=34

Docs

urlencode: https://docs.python.org/3/library/urllib.parse.html#urllib.parse.urlencode

quote_plus: https://docs.python.org/3/library/urllib.parse.html#urllib.parse.quote_plus

balki
fuente