2013-01-04 83 views
5

HTTP響應尋求我從urllib的支持從Python中

response = urllib2.urlopen('http://python.org/') 

HTTP響應最後,我希望能夠seek()響應(至少在初期)內非阻塞流。所以,我希望能有這樣的代碼:

print result.readline() 
result.seek(0) 
print result.readline() 

解決這個問題的最簡單的辦法是StringIOio.BytesIO這樣的:

result = io.BytesIO(response.read()) 

然而,事情是資源我想請求往往非常大,我想在整個下載完成之前開始與他們合作(解析...)。 response.read()正在阻止。我正在尋找一個非阻塞解決方案。

理想的代碼將read(BUFFER_SIZE)從資源和每當需要更多的內容,只是從響應請求更多。我基本上在尋找一個可以做到這一點的包裝類。哦,我需要一個像對象一樣的文件。

我想,我可以寫這樣的:

base = io.BufferedIOBase(response) 
result = io.BufferedReader(base) 

然而,事實證明,這並不工作,我從io module嘗試了不同的類別,但不能得到它的工作。我對任何具有所需行爲的包裝類感到滿意。

回答

0

我寫了自己的包裝類,它保留了第一塊數據。這樣我就可以追溯到開始,分析編碼,文件類型和其他事情。本課爲我解決了這個問題,應該足夠簡單,以適應其他用例。

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) 
+0

1.您可以使用'readline()',它可能讀取整個響應,如果沒有換行符。 2.你應該檢查已保存的數據**的大小加上要保存的行的大小不超過'buffer_size',否則你的緩衝風險大於'buffer_size'。 –

+0

@Piotr Dobrogost謝謝你指出。代碼不完整,當然不安全。它缺少read(),也不支持來自請求模塊的響應。但是,它起到了這個作用。 – dominik

0

使用Requests庫,你可以遍歷響應其正在streamed

要使用Twitter的流API來追蹤關鍵字「請求」:

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) 

爲了能夠尋求你必須保存已經迭代的數據(閱讀)。

+0

這並沒有回答我的問題,因爲沒有'seek'的支持,並且返回一個類似於對象的文件。 – dominik