我可以在Python 2.6.5中使用unllode-ready替换urllib.quote和urllib.unquote吗?

时间:2011-04-05 20:08:45

标签: python unicode urllib

Python的urllib.quoteurllib.unquote在Python 2.6.5中无法正确处理Unicode。这就是:

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'

将值编码为UTF8也不起作用:

In [6]: print urllib.unquote(urllib.quote(u'Cataño'.encode('utf8')))
Cataño

它被认为是一个bug和there is a fix,但不是我的Python版本。

我想要的是类似于urllib.quote / urllib.unquote,但正确处理unicode变量,这样代码就可以了:

decode_url(encode_url(u'Cataño')) == u'Cataño'

有什么建议吗?

4 个答案:

答案 0 :(得分:42)

  

Python的urllib.quote和urllib.unquote无法正确处理Unicode

urllib根本不处理Unicode。根据定义,URL不包含非ASCII字符。当您处理urllib时,您应该只使用字节字符串。如果您希望这些代表Unicode字符,则必须手动对其进行编码和解码。

IRIs可以包含非ASCII字符,将它们编码为UTF-8序列,但此时Python不具有irilib

  

将值编码为UTF8也不起作用:

In [6]: print urllib.unquote(urllib.quote(u'Cataño'.encode('utf8')))
Cataño

啊,现在您正在键入控制台中的Unicode,并在控制台上执行print - Unicode。这通常是不可靠的,尤其是在Windows和with the IPython console中。{/ p>

使用反斜杠序列输入很长的路径,您可以更容易地看到urllib位确实有效:

>>> 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'

答案 1 :(得分:5)

“”“将值编码为UTF8也不起作用”“”...您的代码的结果是str对象,其猜测似乎是以UTF-8编码的输入。你需要解码它或定义“不起作用” - 你期望做什么

注意:我们无需猜测终端的编码和数据类型,请使用print repr(whatever)代替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'
>>>

进行比较:

>>> # 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'
>>>

答案 2 :(得分:1)

我遇到了同样的问题并使用了一个辅助函数来处理非ascii和urllib.urlencode函数(包括quote和unquote):

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')

Unicode URL encode / decode with Python

采用

答案 3 :(得分:1)

所以我遇到了同样的问题:我想将查询参数放在网址中,但其中一些包含了奇怪的字符(变音符号)。

处理编码会产生一个混乱的网址并且很脆弱。

我的解决方案是将每个重音/奇怪的unicode字符替换为其ascii等效字符。由于unidecodeWhat is the best way to remove accents in a Python unicode string?

,这很简单
pip install unidecode

然后

from unidecode import unidecode
print unidecode(u"éèê") 
# prints eee

所以我有一个干净的网址。也适用于中国等。