Python3 urlopen 读取异常 (gzip)
Python3 urlopen read weirdness (gzip)
我从 Schema.org 收到 URL。这是内容类型="text/html"
有时,read() 会按预期运行 b'< !DOCTYPE html> ....'
有时,read() returns something else b'\x1f\x8b\x08\x00\x00\x00\x00 ...'
try:
with urlopen("http://schema.org/docs/releases.html") as f:
txt = f.read()
except URLError:
return
我尝试用 txt = f.read().decode("utf-8").encode()
解决这个问题,但这会导致错误...有时:UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
明显的解决方法是测试第一个字节是否为十六进制并相应地处理它。
我的问题是:这是错误还是其他原因?
编辑
相关 question。显然,有时我会收到 gzipped 流。
最后
我通过将以下代码添加为 proposed here
解决了这个问题
if 31 == txt[0]:
txt = decompress(txt, 16+MAX_WBITS)
问题依旧;为什么这个 return text/html 有时会压缩而其他时候压缩?
您确实收到了 gzip 压缩的响应。您应该可以通过以下方式避免它:
from urllib import request
try:
req = request.Request("http://schema.org/docs/releases.html")
req.add_header('Accept-Encoding', 'identity;q=1')
with request.urlopen(req) as f:
txt = f.read()
except request.URLError:
return
此类别中还有其他问题,但我找不到解决问题实际原因的答案。
Python 的 urllib2.urlopen()
无法透明地处理压缩。它还默认不设置 Accept-Encoding
请求 header。此外,根据 HTTP 标准对这种情况的解释在过去已经发生了变化。
根据RFC2616:
If no Accept-Encoding field is present in a request, the server MAY
assume that the client will accept any content coding. In this case,
if "identity" is one of the available content-codings, then the
server SHOULD use the "identity" content-coding, unless it has
additional information that a different content-coding is meaningful
to the client.
不幸的是(至于用例),RFC7231 将其更改为
If no Accept-Encoding field is in the request, any content-coding is considered acceptable by the user agent.
意思是,当使用 urlopen()
执行请求时,您可以获得服务器决定使用的任何编码的响应,并且响应将是一致的。
schema.org 似乎由 google 托管,即它很可能位于分布式前端负载平衡器网络之后。因此,您得到的不同答案可能是从配置略有不同的负载均衡器返回的。
Google 工程师过去 advocated for the use HTTP compression,所以这也可能是一个有意识的决定。
所以作为一个教训:在使用urlopen()
时我们需要设置Accept-Encoding
.
我从 Schema.org 收到 URL。这是内容类型="text/html"
有时,read() 会按预期运行 b'< !DOCTYPE html> ....'
有时,read() returns something else b'\x1f\x8b\x08\x00\x00\x00\x00 ...'
try:
with urlopen("http://schema.org/docs/releases.html") as f:
txt = f.read()
except URLError:
return
我尝试用 txt = f.read().decode("utf-8").encode()
解决这个问题,但这会导致错误...有时:UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8b in position 1: invalid start byte
明显的解决方法是测试第一个字节是否为十六进制并相应地处理它。
我的问题是:这是错误还是其他原因?
最后 我通过将以下代码添加为 proposed here
解决了这个问题if 31 == txt[0]:
txt = decompress(txt, 16+MAX_WBITS)
问题依旧;为什么这个 return text/html 有时会压缩而其他时候压缩?
您确实收到了 gzip 压缩的响应。您应该可以通过以下方式避免它:
from urllib import request
try:
req = request.Request("http://schema.org/docs/releases.html")
req.add_header('Accept-Encoding', 'identity;q=1')
with request.urlopen(req) as f:
txt = f.read()
except request.URLError:
return
此类别中还有其他问题,但我找不到解决问题实际原因的答案。
Python 的 urllib2.urlopen()
无法透明地处理压缩。它还默认不设置 Accept-Encoding
请求 header。此外,根据 HTTP 标准对这种情况的解释在过去已经发生了变化。
根据RFC2616:
If no Accept-Encoding field is present in a request, the server MAY assume that the client will accept any content coding. In this case, if "identity" is one of the available content-codings, then the server SHOULD use the "identity" content-coding, unless it has additional information that a different content-coding is meaningful to the client.
不幸的是(至于用例),RFC7231 将其更改为
If no Accept-Encoding field is in the request, any content-coding is considered acceptable by the user agent.
意思是,当使用 urlopen()
执行请求时,您可以获得服务器决定使用的任何编码的响应,并且响应将是一致的。
schema.org 似乎由 google 托管,即它很可能位于分布式前端负载平衡器网络之后。因此,您得到的不同答案可能是从配置略有不同的负载均衡器返回的。
Google 工程师过去 advocated for the use HTTP compression,所以这也可能是一个有意识的决定。
所以作为一个教训:在使用urlopen()
时我们需要设置Accept-Encoding
.