2013-01-04 3 views
5

ho una risposta HTTP da urllibflusso non bloccante che supporta cercare di risposta HTTP in Python

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

Alla fine, voglio essere in grado di seek() all'interno della risposta (almeno all'inizio). Allora voglio essere in grado di avere codice come questo:

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

La soluzione più semplice a questo problema è StringIO o io.BytesIO come questo:

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

Tuttavia, il fatto è che le risorse voglio la richiesta tende ad essere molto grande e voglio iniziare a lavorare con loro (analisi ...) prima che l'intero download sia finito. response.read() sta bloccando. Sto cercando una soluzione non bloccante.

Il codice ideale sarebbe read(BUFFER_SIZE) dalla risorsa e ogni volta che è necessario più contenuto, è sufficiente richiedere più dalla risposta. Sto fondamentalmente cercando una classe wrapper in grado di farlo. Oh, e ho bisogno di un file come oggetto.

ho pensato, potrei scrivere qualcosa di simile:

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

Tuttavia, si scopre che questo non funziona e ho cercato classi diverse dalla io module ma non ha potuto farlo funzionare. Sono felice con qualsiasi classe wrapper che abbia il comportamento desiderato.

risposta

0

Ho scritto la mia classe wrapper che conserva il primo blocco di dati. In questo modo posso tornare all'inizio, analizzare la codifica, il tipo di file e altre cose. Questa classe risolve il problema per me e dovrebbe essere abbastanza semplice da adattarsi ad altri casi d'uso.

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. Si utilizza 'readline()' che potrebbe potenzialmente leggere l'intera risposta se non ci sono interruzioni di riga. 2. Si dovrebbe verificare se la dimensione dei dati già salvati ** più ** la dimensione della riga da salvare non superi 'buffer_size' altrimenti si rischia di buffering più di' buffer_size'. –

+0

@Piotr Dobrogost Grazie per averlo indicato. Il codice non è completo e non è sicuramente sicuro. Manca read() e inoltre non supporta le risposte dal modulo delle richieste. Tuttavia, serve allo scopo. – dominik

0

Utilizzando Requests biblioteca è possibile iterare risposta che è l'essere streamed:

Per utilizzare l'API di Twitter Streaming per monitorare la parola chiave “richieste”:

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) 

Per essere in grado di cercare di salvare i dati che hai già ripetuto (leggi).

+0

Questo non risponde alla mia domanda poiché non esiste un supporto per 'seek' e restituisce un file come oggetto. – dominik

Problemi correlati