Есть ли в Python 2.6.5 заменитель, готовый к Юникоду, который я могу использовать для urllib.quote и urllib.unquote? - PullRequest
41 голосов
/ 06 апреля 2011

Python urllib.quote и urllib.unquote неправильно обрабатывают Unicode в Python 2.6.5.Вот что происходит:

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

Это распознается как ошибка и есть исправление ,но не для моей версии Python.

Мне нужно что-то похожее на urllib.quote / urllib.unquote, но правильно обрабатывает переменные Юникода, так что этот код будет работать:

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

Есть рекомендации?

Ответы [ 4 ]

42 голосов
/ 09 апреля 2011

Pyll: urllib.quote и urllib.unquote неправильно обрабатывают Unicode

urllib вообще не обрабатывает Unicode.URL-адреса не содержат не-ASCII символов, по определению.Когда вы имеете дело с urllib, вы должны использовать только байтовые строки.Если вы хотите, чтобы они представляли символы Unicode, вам придется кодировать и декодировать их вручную.

IRI может содержать символы не ASCII, кодируя их как последовательности UTF-8, но Python не делаетt, на данный момент, есть irilib.

Кодирование значения в UTF8 также не работает:

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

Ах, хорошо, теперь вынабрав Unicode в консоли и выполнив print -Unicode для консоли.Как правило, это ненадежно, особенно в Windows и в вашем случае с консолью IPython .

Введите длинный путь с последовательностями с обратной косой чертой, и вам будет легче увидеть, что бит 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'
5 голосов
/ 06 апреля 2011

"" "Кодирование значения в UTF8 также не работает" "" ... результатом вашего кода является объект str, который, по предположению, является входом, закодированным в UTF-8. Вам нужно расшифровать его или определить «не работает» - что вы ожидаете do ?

Примечание. Чтобы нам не приходилось угадывать кодировку вашего терминала и тип ваших данных, используйте 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'
>>>
1 голос
/ 04 сентября 2015

Итак, у меня была та же проблема: я хотел поместить параметры запроса в URL, но некоторые из них содержали странные символы (диакритические знаки).

Работа с кодировкой приводила к беспорядочной ссылке и была хрупкой.

Мое решение состояло в том, чтобы заменить каждый акцент / странный символ юникода на его эквивалент ascii.Это просто благодаря unidecode: Каков наилучший способ удаления акцентов в строке Unicode Python?

pip install unidecode

затем

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

, поэтому у меня естьчистый URL.Также работает для китайского и т. Д.

1 голос
/ 04 июня 2015

Я столкнулся с той же проблемой и использовал вспомогательную функцию для работы с не-ascii и функцией urllib.urlencode (которая включает в себя кавычки и кавычки):

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

принято из URL кодирования / декодирования Unicode с Python

...