【问题标题】:urllib.quote() throws KeyErrorurllib.quote() 抛出 KeyError
【发布时间】:2013-02-13 11:11:47
【问题描述】:

为了对 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。使key不存在并抛出异常。

所以,我只是在 try-except 块中调用 ''.join(map(quoter, s)) 之前修改了 s = [el.upper().replace("\\X","%") for el in s]。现在它工作正常。

但是我很烦我所做的是正确的方法还是会产生任何其他问题? 而且我确实有 200 多个 linux 实例,很难在所有实例中部署此修复程序。

【问题讨论】:

  • 这是带有 unicode 值的 Python 2 吗?它适用于已经编码的数据。
  • 您确实不会收到urllib.quote('sch\xe9nefeld') 的错误。您收到urllib.quote(u'sch\xe9nefeld') 的错误(注意u'' unicode 文字)。
  • @MartijnPieters 所以cmdString = "http://baseurl" + quote("schönefeld") 这应该像cmdString=u"http://baseurl"+quote(u"schönefeld")
  • 不,你误会我了。我声明该错误仅在您提供 quote() unicode 值时发生。对于字节字符串(已经编码),这不会发生。

标签: python unicode urllib2 urlencode urllib


【解决方案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'

但是,编码取决于服务器将接受的内容。最好坚持发送原始表单时使用的编码。

【讨论】:

  • utf-8 的大小写比您的答案暗示的要强。 All major browsers use utf-8 在构建 URI 时进行百分比编码之前。 IRIURI 必须使用 utf-8 进行转换。旧版服务器上使用其他编码。
  • @J.F.Sebastian:当然,URI 的路径元素使用 UTF-8。但这是查询部分。浏览器在查询字符串中用于编码的定义不太明确,过去一直基于表单所源自的 HTML 页面的编码。
【解决方案2】:

只需将字符串转换为 unicode,我就解决了这个问题。

这里是sn-p:

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 完全相同的错误,但在我的情况下,问题是 map(quoter,s) 试图查找不在 _safe_map 中的密钥 u'\xe9'。但是\xe9 是,所以我通过在s 中将u'\xe9' 替换为\xe9 解决了这个问题。

    此外,return 语句不应该在 try/except 内吗?我还必须更改它以完全解决问题。

    【讨论】:

      猜你喜欢
      • 2021-03-03
      • 2022-01-15
      • 2018-08-13
      • 1970-01-01
      • 1970-01-01
      • 2019-11-29
      • 2012-03-26
      • 1970-01-01
      相关资源
      最近更新 更多