u'\xc3\xa8'
是 Python 2 中具有 2 个代码点的 Unicode 字符串,即 Ã
和 ¨
。接下来请注意,'\xc3\xa8'
是 Python 2 中的字节字符串,表示字符 è
的 UTF8 编码。因此,尽管 u'\xc3\xa8'
和 '\xc3\xa8'
看起来非常相似,但它们是两种非常不同的东西。现在,如果我们在浏览器中尝试访问
https://www.sainsburys.co.uk/shop/gb/groceries/chablis/chablis-premièr-cru-brocard-75cl
,一切都应该顺利。如果我在 ipython 会话中定义:
unicode_url = u'https://www.sainsburys.co.uk/shop/gb/groceries/chablis/chablis-premièr-cru-brocard-75cl'
然后我可以打印它并查看与浏览器URL栏中输入的内容相同,太好了。现在让我们试着使用Python请求获取它。
首先,我天真地尝试将Unicode URL直接传递给requests:
requests.get(unicode_url)
。不行,404错误,没问题,URL应该进行编码,所以我尝试了requests.get(unicode_url.encode('utf8'))
。还是404错误。没关系,也许我需要对URL进行编码,所以我尝试了requests.get(urllib.quote(unicode_url.encode('utf8')))
... 它完全不喜欢那样做。但是,回想一下我在开头提到的Unicode和字节字符串对象之间的相似之处,我也尝试过:
requests.get('http://www.sainsburys.co.uk/shop/gb/groceries/chablis/chablis-premièr-cru-brocard-75cl')
令我惊讶的是它有效并返回成功的200。
requests在这里做了什么?
编辑:作为另一个实验(这次是在Scrapy shell中)
from scrapy.http import Request
unicode_url = u'https://www.sainsburys.co.uk/shop/gb/groceries/chablis/chablis-premièr-cru-brocard-75cl'
fetch(Request(unicode_url))
绝对没有问题!那么为什么Scrapy和浏览器可以毫无问题地处理它,但是python-requests不能呢?为什么替代url在python-requests中可以工作,但在浏览器或Scrapy中却不行。
Latin1与UTF8
还有一个事实是
print unicode_url.encode('utf8').decode('latin1')
u'https://www.sainsburys.co.uk/shop/gb/groceries/chablis/chablis-premièr-cru-brocard-75cl'
一般来说,我认为对于仅限于拉丁字符的Unicode字符而言,如果您有一个Unicode字符串,例如
u'\xe8'
,那么您可以通过将其编码为Latin1将其转换为相同格式的字节字符串,即u'è'=u'\xe8'
和u'\xe8'.encode('latin1') = '\xe8'
(右侧的对象是使用与表示è
的Unicode代码点相同的形式在Latin1中进行编码的字节字符串)。In [95]: print u'è'.encode('utf8').decode('latin1')
è
并且同样地,
In [94]: print u'è'.encode('latin1').decode('utf8')
è
我在想罪犯会不会是
def prepare_url(self, url, params):
"""Prepares the given HTTP URL."""
#: Accept objects that have string representations.
#: We're unable to blindly call unicode/str functions
#: as this will include the bytestring indicator (b'')
#: on python 3.x.
#: https://github.com/kennethreitz/requests/pull/2238
if isinstance(url, bytes):
url = url.decode('utf8')
else:
url = unicode(url) if is_py2 else str(url)
来源于requests/models.py
文件。
# coding: utf-8
这一行吗? - tdelaneypython-2.7
(或类似的)标签吗?然后迅速转移到 Python 3,因为那里已经修复了 Unicode 支持问题?(微笑) - tdelaneylen(u"premièr")
是7还是8? - tdelaney