netloc - ¿Existe un sustituto listo para Unicode que pueda usar para urllib.quote y urllib.unquote en Python 2.6.5?
uri % python (4)
Python''s urllib.quote
y urllib.unquote
no manejan Unicode correctamente en Python 2.6.5. Esto es lo que pasa:
In [5]: print urllib.unquote(urllib.quote(u''Cataño''))
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
/home/kkinder/<ipython console> in <module>()
/usr/lib/python2.6/urllib.pyc in quote(s, safe)
1222 safe_map[c] = (c in safe) and c or (''%%%02X'' % i)
1223 _safemaps[cachekey] = safe_map
-> 1224 res = map(safe_map.__getitem__, s)
1225 return ''''.join(res)
1226
KeyError: u''/xc3''
La codificación del valor de UTF8 tampoco funciona:
In [6]: print urllib.unquote(urllib.quote(u''Cataño''.encode(''utf8'')))
Cataño
Se reconoce como un error y existe una solución , pero no para mi versión de Python.
Lo que me gustaría es algo similar a urllib.quote / urllib.unquote, pero maneja las variables Unicode correctamente, de modo que este código funcione:
decode_url(encode_url(u''Cataño'')) == u''Cataño''
¿Alguna recomendación?
Python''s urllib.quote y urllib.unquote no manejan Unicode correctamente
urllib
no maneja Unicode en absoluto. Las URL no contienen caracteres que no sean ASCII, por definición. Cuando se trata de urllib
solo debe usar cadenas de bytes. Si desea que estos representen caracteres Unicode, deberá codificarlos y decodificarlos manualmente.
IRIs pueden contener caracteres no ASCII, codificándolos como secuencias UTF-8, pero Python no tiene, en este punto, un irilib
.
La codificación del valor de UTF8 tampoco funciona:
In [6]: print urllib.unquote(urllib.quote(u''Cataño''.encode(''utf8'')))
Cataño
Ah, bueno ahora estás escribiendo Unicode en una consola, y haciendo print
-Unicode a la consola. Esto generalmente no es confiable, especialmente en Windows y en su caso con la consola IPython .
Tíralo a lo largo con secuencias de barra invertida y podrás ver más fácilmente que la urllib
realmente funciona:
>>> u''Cata/u00F1o''.encode(''utf-8'')
''Cata/xC3/xB1o''
>>> urllib.quote(_)
''Cata%C3%B1o''
>>> urllib.unquote(_)
''Cata/xC3/xB1o''
>>> _.decode(''utf-8'')
u''Cata/xF1o''
"" "La codificación del valor en UTF8 tampoco funciona" "" ... el resultado de tu código es un objeto str
que, en un intento, parece ser la entrada codificada en UTF-8. Necesita decodificarlo o definir "no funciona", ¿ qué espera?
Nota: Para que no tengamos que adivinar la codificación de su terminal y el tipo de sus datos, use print repr(whatever)
lugar de print whatever
.
>>> # Python 2.6.6
... from urllib import quote, unquote
>>> s = u"Cata/xf1o"
>>> q = quote(s.encode(''utf8''))
>>> u = unquote(q).decode(''utf8'')
>>> for x in (s, q, u):
... print repr(x)
...
u''Cata/xf1o''
''Cata%C3%B1o''
u''Cata/xf1o''
>>>
Para comparacion:
>>> # Python 3.2
... from urllib.parse import quote, unquote
>>> s = "Cata/xf1o"
>>> q = quote(s)
>>> u = unquote(q)
>>> for x in (s, q, u):
... print(ascii(x))
...
''Cata/xf1o''
''Cata%C3%B1o''
''Cata/xf1o''
>>>
Entonces tuve el mismo problema: quería poner los parámetros de consulta en una url, pero algunos de ellos contenían caracteres extraños (signos diacríticos).
Lidiar con la codificación dio una url desordenada y era frágil.
Mi solución fue reemplazar cada acento / extraño carácter unicode a su equivalente ascii. Es sencillo gracias a unidecode
: ¿Cuál es la mejor manera de eliminar acentos en una cadena unicode de Python?
pip install unidecode
entonces
from unidecode import unidecode
print unidecode(u"éèê")
# prints eee
entonces tengo una url limpia. También funciona para chino, etc.
Me encontré con el mismo problema y usé una función auxiliar para manejar la función no-ascii y urllib.urlencode (que incluye comillas y comillas):
def utf8_urlencode(params):
import urllib as u
# problem: u.urlencode(params.items()) is not unicode-safe. Must encode all params strings as utf8 first.
# UTF-8 encodes all the keys and values in params dictionary
for k,v in params.items():
# TRY urllib.unquote_plus(artist.encode(''utf-8'')).decode(''utf-8'')
if type(v) in (int, long, float):
params[k] = v
else:
try:
params[k.encode(''utf-8'')] = v.encode(''utf-8'')
except Exception as e:
logging.warning( ''**ERROR utf8_urlencode ERROR** %s'' % e )
return u.urlencode(params.items()).decode(''utf-8'')
Adoptado desde la codificación / decodificación de URL Unicode con Python