如何从urllib.urlopen()返回的“类文件对象”创建GzipFile实例?

15 投票
3 回答
5721 浏览
提问于 2025-04-16 07:12

我正在用Python玩Stack Overflow的API。我想解码API返回的gzipped响应。

import urllib, gzip

url = urllib.urlopen('http://api.stackoverflow.com/1.0/badges/name')
gzip.GzipFile(fileobj=url).read()

根据urllib2的文档urlopen“返回一个类似文件的对象”。

但是,当我在用它创建的GzipFile对象上运行read()时,我遇到了这个错误:

AttributeError: addinfourl instance has no attribute 'tell'

据我所知,这个错误是由urlopen返回的对象引起的。

它似乎也没有seek功能,因为当我尝试这样做时,我又遇到了一个错误:

url.read()
url.seek(0)

这个对象到底是什么?我该如何从它创建一个正常工作的GzipFile实例呢?

3 个回答

0

这是对@stefanw的回答的一个新更新,可能有人觉得使用那么多内存太贵了。

感谢这篇文章(https://www.enricozini.org/blog/2011/cazzeggio/python-gzip/,它解释了为什么gzip不起作用),解决办法是使用Python3。

import urllib.request
import gzip

response = urllib.request.urlopen('http://api.stackoverflow.com/1.0/badges/name')
with gzip.GzipFile(fileobj=response) as f:
    for line in f:
        print(line)
8
import urllib2
import json
import gzip
import io

url='http://api.stackoverflow.com/1.0/badges/name'
page=urllib2.urlopen(url)
gzip_filehandle=gzip.GzipFile(fileobj=io.BytesIO(page.read()))
json_data=json.loads(gzip_filehandle.read())
print(json_data)

io.BytesIO 是适用于 Python 2.6 及以上版本的。如果你使用的是更早版本的 Python,可以用 cStringIO.StringIO 来代替。

10

urlopen文档列出了返回对象支持的方法。我建议把这个对象放在另一个类里,这样可以支持gzip所需要的方法。

另一种选择是:调用响应对象的read方法,把结果放进一个StringIO对象里(这个对象应该支持gzip所需的所有方法)。不过这样可能会稍微消耗更多资源。

例如:

import gzip
import json
import StringIO
import urllib

url = urllib.urlopen('http://api.stackoverflow.com/1.0/badges/name')
url_f = StringIO.StringIO(url.read())
g = gzip.GzipFile(fileobj=url_f)
j = json.load(g)

撰写回答