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
等等。
我在Windows上尝试打印语句(使用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中的每个元素,都会调用quoter函数,最后将列表用''连接起来并返回。
对于非ASCII字符 è
,它的对应键是 %E8
,这个键在 _safe_map
变量中存在。但是当我调用 quote('è')
时,它会查找键 \xe8
。所以这个键不存在,因此抛出了异常。
所以,我在调用 ''.join(map(quoter, s))
之前,修改了 s = [el.upper().replace("\\X","%") for el in s]
,并放在了try-except块中。现在它运行得很好。
但我在想,我这样做是否是正确的方法,或者会不会引发其他问题?而且我有200多个Linux实例,要在所有实例中部署这个修复非常困难。
3 个回答
我遇到的错误和@underscore的一模一样,但我的情况是,map(quoter,s)在找一个叫u'\xe9'
的键,而这个键在<_safe_map>里找不到。不过\xe9
是存在的,所以我通过把u'\xe9'
替换成\xe9
来解决了这个问题。
另外,return
语句不应该放在try/except
里面吗?我也需要改这个,才能完全解决问题。
我只是把字符串转换成了unicode格式,这样就解决了问题。
下面是代码片段:
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
你想要把Unicode数据转成可以在网址中安全使用的格式,所以你需要想办法把它变成安全的字节。
首先,把这个字符串编码成字节。通常我们会用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'
不过,编码方式其实要看服务器能接受什么。最好是用发送原始数据时的编码方式。