我有来自urllib的http响应
response = urllib2.urlopen('http://python.org/')
最终,我希望能够在响应中seek()
(至少在开头)。所以我希望能够拥有这样的代码:
print result.readline()
result.seek(0)
print result.readline()
此问题的最简单解决方案是StringIO
或io.BytesIO
,如下所示:
result = io.BytesIO(response.read())
然而,问题是我想要请求的资源往往非常大,我想在整个下载完成之前开始使用它们(解析...)。 response.read()
正在阻止。我正在寻找一种非阻塞解决方案。
理想代码将来自资源read(BUFFER_SIZE)
,无论何时需要更多内容,只需从响应中请求更多内容。我基本上正在寻找一个可以做到这一点的包装类。哦,我需要一个像对象一样的文件。
我想,我可以这样写:
base = io.BufferedIOBase(response)
result = io.BufferedReader(base)
然而,事实证明这不起作用,我尝试了io module中的不同类,但无法使其正常工作。我对任何具有所需行为的包装类感到满意。
答案 0 :(得分:1)
我编写了自己的包装类,它保留了第一块数据。这样我就可以回头查看,分析编码,文件类型等等。这个类为我解决了这个问题,应该足够简单以适应其他用例。
class BufferedFile(object):
''' A buffered file that preserves the beginning of a stream up to buffer_size
'''
def __init__(self, fp, buffer_size=1024):
self.data = cStringIO.StringIO()
self.fp = fp
self.offset = 0
self.len = 0
self.fp_offset = 0
self.buffer_size = buffer_size
@property
def _buffer_full(self):
return self.len >= self.buffer_size
def readline(self):
if self.len < self.offset < self.fp_offset:
raise BufferError('Line is not available anymore')
if self.offset >= self.len:
line = self.fp.readline()
self.fp_offset += len(line)
self.offset += len(line)
if not self._buffer_full:
self.data.write(line)
self.len += len(line)
else:
line = self.data.readline()
self.offset += len(line)
return line
def seek(self, offset):
if self.len < offset < self.fp_offset:
raise BufferError('Cannot seek because data is not buffered here')
self.offset = offset
if offset < self.len:
self.data.seek(offset)
答案 1 :(得分:-1)
使用Twitter Streaming API跟踪关键字“requests”:
import requests
import json
r = requests.post('https://stream.twitter.com/1/statuses/filter.json',
data={'track': 'requests'}, auth=('username', 'password'), stream=True)
for line in r.iter_lines():
if line: # filter out keep-alive new lines
print json.loads(line)
为了能够寻找你必须保存已经迭代(读取)的数据。