Как я могу создать экземпляр GzipFile из "файлового объекта", который возвращает urllib.urlopen()?
Я играю с API переполнения стека, используя Python. Я пытаюсь декодировать сжатые ответы, которые дает API.
import urllib, gzip
url = urllib.urlopen('http://api.stackru.com/1.0/badges/name')
gzip.GzipFile(fileobj=url).read()
Согласно документации urllib2, urlopen
"Возвращает файл-подобный объект".
Тем не менее, когда я бегу read()
на объекте GzipFile, который я создал, используя его, я получаю эту ошибку:
AttributeError: addinfourl instance has no attribute 'tell'
Насколько я могу судить, это происходит от объекта, возвращенного urlopen
,
Похоже, он тоже не ищет, так как я получаю ошибку, когда делаю это:
url.read()
url.seek(0)
Что именно это за объект и как мне создать функционирующий GzipFile
экземпляр из этого?
2 ответа
Документы urlopen содержат список поддерживаемых методов возвращаемого объекта. Я рекомендую обернуть объект в другой класс, который поддерживает методы, ожидаемые gzip.
Другой вариант: вызвать метод read объекта ответа и поместить результат в объект StringIO (который должен поддерживать все методы, которые ожидает gzip). Это может быть немного дороже, хотя.
Например
import gzip
import json
import StringIO
import urllib
url = urllib.urlopen('http://api.stackru.com/1.0/badges/name')
url_f = StringIO.StringIO(url.read())
g = gzip.GzipFile(fileobj=url_f)
j = json.load(g)
import urllib2
import json
import gzip
import io
url='http://api.stackru.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
для Python2.6+. Для более старых версий Python вы можете использовать cStringIO.StringIO
,
Вот новое обновление для ответа @tefanw, которому может показаться, что использовать такой объем памяти слишком дорого.
Благодаря этой статье (https://www.enricozini.org/blog/2011/cazzeggio/python-gzip/ она объясняет, почемуgzip
не работает), решение - использовать Python3.
import urllib.request
import gzip
response = urllib.request.urlopen('http://api.stackru.com/1.0/badges/name')
with gzip.GzipFile(fileobj=response) as f:
for line in f:
print(line)