Urllib.quote() бросает KeyError
Чтобы закодировать URI, я использовал urllib.quote("schönefeld")
, но когда в строке присутствуют некоторые символы, отличные от ascii, он поддерживает
KeyError: u'\xe9'
Code: return ''.join(map(quoter, s))
Мои строки ввода köln, brønshøj, schönefeld
и т.д.
Когда я пробовал просто печатать заявления в окнах (с использованием python2.7, pyscripter IDE). Но в Linux он вызывает исключение (я думаю, платформа не имеет значения).
Вот что я пытаюсь:
from commands import getstatusoutput
queryParams = "schönefeld";
cmdString = "http://baseurl" + quote(queryParams)
print getstatusoutput(cmdString)
Изучение причины проблемы:
в urllib.quote()
, на самом деле исключение выбрано в return ''.join(map(quoter, s))
.
Код в urllib:
def quote(s, safe='/'):
if not s:
if s is None:
raise TypeError('None object cannot be quoted')
return s
cachekey = (safe, always_safe)
try:
(quoter, safe) = _safe_quoters[cachekey]
except KeyError:
safe_map = _safe_map.copy()
safe_map.update([(c, c) for c in safe])
quoter = safe_map.__getitem__
safe = always_safe + safe
_safe_quoters[cachekey] = (quoter, safe)
if not s.rstrip(safe):
return s
return ''.join(map(quoter, s))
Причиной исключения является ''.join(map(quoter, s))
, для каждого элемента из s будет вызываться функция-циферблат, и, наконец, список будет соединен с символом '' и возвращен.
Для non-ascii char è
эквивалентный ключ будет %E8
, который представлен в переменной _safe_map
. Но когда я вызываю цитату ('è'), она ищет ключ \xe8
. Так что ключ не существует и исключение выбрано.
Итак, я просто модифицировал s = [el.upper().replace("\\X","%") for el in s]
перед вызовом ''.join(map(quoter, s))
в блоке try-except. Теперь он отлично работает.
Но я раздражаю то, что я сделал, это правильный подход или он создаст любую другую проблему?
А также у меня есть 200+ экземпляров Linux, которые очень сложно развернуть это исправление во всех случаях.
Ответы
Ответ 1
Вы пытаетесь указать данные Unicode, поэтому вам нужно решить, как превратить это в безопасные по URL-адреса байты.
Сначала кодируйте строку в байты. UTF-8 часто используется:
>>> import urllib
>>> urllib.quote(u'sch\xe9nefeld')
/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py:1268: UnicodeWarning: Unicode equal comparison failed to convert both arguments to Unicode - interpreting them as being unequal
return ''.join(map(quoter, s))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib.py", line 1268, in quote
return ''.join(map(quoter, s))
KeyError: u'\xe9'
>>> urllib.quote(u'sch\xe9nefeld'.encode('utf8'))
'sch%C3%A9nefeld'
Однако кодировка зависит от того, что сервер примет. Лучше всего придерживаться кодировки, с которой была отправлена оригинальная форма.
Ответ 2
Просто преобразовывая строку в Юникод, я решил проблему.
Вот фрагмент:
try:
unicode(mystring, "ascii")
except UnicodeError:
mystring = unicode(mystring, "utf-8")
else:
pass
Подробное описание решения можно найти на http://effbot.org/pyfaq/what-does-unicodeerror-ascii-decoding-encoding-error-ordinal-not-in-range-128-mean.htm
Ответ 3
У меня была такая же ошибка, как и @underscore, но в моем случае проблема заключалась в том, что карта (quoter, s) пыталась найти ключ u'\xe9'
, который не был в _safe_map
. Однако \xe9
был, поэтому я решил проблему, заменив u'\xe9'
на \xe9
в s
.
Кроме того, должен ли оператор return
находиться в пределах try/except
? Мне также пришлось изменить это, чтобы полностью решить проблему.