所涉及的服务器给你提供了一个压缩响应。此服务器也非常有问题,它发送以下标头:
$ curl -D - -o /dev/null -s -H 'Accept-Encoding: gzip, deflate' http://www.wrcc.dri.edu/WRCCWrappers.py?sodxtrmts+028815+por+por+pcpn+none+mave+5+01+F
HTTP/1.1 200 OK
Date: Tue, 06 Jan 2015 17:46:49 GMT
Server: Apache
<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd"><html xmlns="http: //www.w3.org/1999/xhtml" lang="en-US">
Vary: Accept-Encoding
Content-Encoding: gzip
Content-Length: 3659
Content-Type: text/html
<!DOCTYPE..>
不是有效的 HTTP 头部信息。因此,过了 Server
后面的其余头部信息会被忽略。为什么服务器会插入这段内容还不清楚;很可能是因为 WRCCWrappers.py
是一个 CGI 脚本,它不输出头部信息,但在 doctype 行之后包含了一个双换行符,欺骗 Apache 服务器在那里插入额外的头部信息。
因此,requests
也无法检测到数据是否经过 gzip 编码。数据都在那里,你只需要解码它。但如果数据不完整,你就无法解码。
解决方法是告诉服务器不要压缩:
headers = {'Accept-Encoding': 'identity'}
r = requests.get(url, headers=headers)
并且将返回未压缩的响应。
顺便提一下,在Python 2上,HTTP头解析器不是那么严格,可以将doctype声明为一个头部:
>>> pprint(dict(r.headers))
{'<!doctype html public "-//w3c//dtd xhtml 1.0 transitional//en" "dtd/xhtml1-transitional.dtd"><html xmlns="http': '//www.w3.org/1999/xhtml" lang="en-US">',
'connection': 'Keep-Alive',
'content-encoding': 'gzip',
'content-length': '3659',
'content-type': 'text/html',
'date': 'Tue, 06 Jan 2015 17:42:06 GMT',
'keep-alive': 'timeout=5, max=100',
'server': 'Apache',
'vary': 'Accept-Encoding'}
并且 content-encoding
信息会保留,所以 requests
会为您解码内容,如预期的那样。
requests
是基于urllib3
构建的。然而,问题在于这里的服务器。 - Martijn Pieters