这个gzip格式有什么问题?
我用下面的Python代码从服务器下载带有gzip压缩的网页:
url = "http://www.v-gn.de/wbb/"
import urllib2
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
content = response.read()
response.close()
import gzip
from StringIO import StringIO
html = gzip.GzipFile(fileobj=StringIO(content)).read()
这个方法通常是有效的,但在特定的URL上会出现一个struct.error
的错误。如果我用wget并加上“Accept-encoding”这个头信息,也会得到类似的结果。不过,浏览器似乎能正常解压缩响应。
所以我想问的是:有没有办法让我这段Python代码在不去掉“Accept-encoding”头信息的情况下,解压缩HTTP响应呢?
为了完整起见,这里是我用wget的那行代码:
wget --user-agent="Mozilla" --header="Accept-Encoding: gzip,deflate" http://www.v-gn.de/wbb/
3 个回答
3
你可以通过从urllib2.HTTPHandler这个类派生来创建你的处理器,并重写http_open()方法。
import gzip
from StringIO import StringIO
import httplib, urllib, urllib2
class GzipHandler(urllib2.HTTPHandler):
def http_open(self, req):
req.add_header('Accept-encoding', 'gzip')
r = self.do_open(httplib.HTTPConnection, req)
if (
'Content-Encoding'in r.headers and
r.headers['Content-Encoding'] == 'gzip'
):
fp = gzip.GzipFile(fileobj=StringIO(r.read()))
else:
fp = r
response = urllib.addinfourl(fp, r.headers, r.url, r.code)
response.msg = r.msg
return respsone
然后构建你的opener。
def retrieve(url):
request = urllib2.Request(url)
opener = urllib2.build_opener(GzipHandler)
return opener.open(request)
这个方法的不同之处在于,它会检查服务器是否返回了gzip格式的响应,而且这个检查是在请求的时候进行的,而不是请求之后。
想了解更多信息,可以查看:
3
我运行了你指定的命令。它把一个压缩的数据下载到了 index.html
文件里。我把 index.html
改名成了 index.html.gz
。然后我试着用 gzip -d index.html.gz
来解压,但出现了一个错误:gzip: index.html.gz: unexpected end of file
,意思是文件的结尾有点问题。
第二次我试了 zcat index.html.gz
,这个命令成功了,除了在 </html>
标签后面又出现了之前的那个错误。
$ zcat index.html.gz
...
</td>
</tr>
</table>
</body>
</html>
gzip: index.html.gz: unexpected end of file
服务器可能有问题。
4
看起来你可以在 gzip.GzipFile
对象上使用 readline()
方法,但如果用 read()
方法的话,会因为文件突然结束而出现 struct.error
的错误。
因为 readline
方法在大部分情况下都能正常工作(除了在文件的最后一部分),你可以尝试这样做:
import urllib2
import StringIO
import gzip
import struct
url = "http://www.v-gn.de/wbb/"
request = urllib2.Request(url)
request.add_header('Accept-encoding', 'gzip')
response = urllib2.urlopen(request)
content = response.read()
response.close()
fh=StringIO.StringIO(content)
html = gzip.GzipFile(fileobj=StringIO.StringIO(content))
try:
for line in html:
line=line.rstrip()
print(line)
except struct.error:
pass