请求返回字节,我无法解码它们。

43

本质上,我向一个网站发出请求并获得了一个字节响应:b'[{"geonameId:"703448"}..........'. 我感到困惑,因为尽管它是字节类型,但它非常易读,看起来像一个JSON列表。从运行r.encoding返回的ISO-859-1可以知道响应以Latin1编码,我已经尝试解码它,但只返回一个空字符串。以下是我目前的代码:

r = response.content
string = r.decode("ISO-8859-1")
print (string)

这是打印空行的位置。但是,当我运行时

len(string)

我收到了一个编码为31023的字节,如何解码它而不得到空字符串?


在Python 2.x中,b前缀会使包含的字符串变成类型str,你可能已经在某个地方隐藏了一些编码字符。在Python 3.x中,你将收到一个bytes字面量。为什么你认为需要执行任何编码/解码操作呢? - Mike McMahon
因为我需要解析JSON,所以我尝试循环遍历它:使用 for i in range(len(contents)): print content[i],但它只是打印出了许多数字。 - koda gates
4个回答

37

你尝试使用json模块解析过它吗?

import json
parsed = json.loads(response.content)

9
是的,我收到了:JSON 对象必须是 str 类型,而不是 bytes 类型 - koda gates
4
当你执行json.loads(response.content.decode('latin1'))时,它会将响应内容解码为Latin-1格式并将其转换为JSON对象。 - mzc
响应对象中应该有一个标题告诉您它使用的编码方式。您应该使用该编解码器对内容进行解码,否则任何不寻常的字符(表情符号、重音符号、某些引号字符等)都会变成乱码。请参见@salah的答案。 - drevicko
@mzc 请直接在答案中添加 content.decode 注释。 - Martin Thoma
@mzc,decode('latin1')并不总是有效的,在内容类型为text/html; charset=UTF-8的情况下,它会失败。 - Anu

31

另一个解决方案是使用response.text,它以Unicode格式返回内容。

Type:        property
String form: <property object at 0x7f76f8c79db8>
Docstring:  
Content of the response, in unicode.

If Response.encoding is None, encoding will be guessed using
``chardet``.

The encoding of the response content is determined based solely on HTTP
headers, following RFC 2616 to the letter. If you can take advantage of
non-HTTP knowledge to make a better guess at the encoding, you should
set ``r.encoding`` appropriately before accessing this property.

5
这个想法比被接受的答案好多了,因为它会使用适当的编码方式。 - drevicko
1
是的,这就是文档中建议的做法:http://docs.python-requests.org/en/master/user/quickstart/#response-content - Jérôme

13

r.textr.content两种。前者是字符串,后者是字节。

你想要:

import json

data = json.loads(r.text)

我有一个类似的问题,当我使用r.text时,它是空的。 - j_allen_morris
1
那么可能是服务器没有返回任何内容。 - Martin Thoma
我正在请求网页(http://www.dockethound.com)的源代码/HTML,当我使用r.content时,它会显示出来。 - j_allen_morris

3

在爬取网页时,我使用了beautifulsoup4requests遇到了类似的问题,不过response.textresponse.content看起来都是字节。

响应头中包含编码为UTF-8的文本'Content-Type': 'text/html; charset=UTF-8',同时响应头中也有'Content-Encoding': 'br'。后来发现我没有在环境中安装brotlipy,而运行pip install brotlipy解决了我的问题。我原以为chardetcchardet就足够了,但数据需要正确地解压缩。

同样的问题可以通过这里的方式解决,我在此引用该答案,因为直到我明确搜索brotli压缩时才找到它。


我遇到了同样的问题,安装brotlipy解决了字节响应的问题。 - EMartins
而且没有必要使用json模块解析响应。只需要使用response.text就可以了。 - EMartins

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接