2013-01-04 29 views
5

Tôi có một phản ứng http từ urllibsuối chặn không hỗ trợ tìm kiếm từ phản ứng http bằng Python

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

Cuối cùng, tôi muốn để có thể seek() trong phản ứng (ít nhất là đến đầu). Vì vậy, tôi muốn để có thể có mã như thế này:

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

Giải pháp đơn giản nhất cho vấn đề này là StringIO hoặc io.BytesIO như thế này:

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

Tuy nhiên, điều được rằng các nguồn lực Tôi muốn yêu cầu có xu hướng rất lớn và tôi muốn bắt đầu làm việc với chúng (phân tích cú pháp ...) trước khi toàn bộ quá trình tải xuống hoàn tất. response.read() đang chặn. Tôi đang tìm một giải pháp không chặn.

Mã lý tưởng sẽ read(BUFFER_SIZE) từ tài nguyên và bất cứ khi nào cần thêm nội dung, chỉ cần yêu cầu thêm từ phản hồi. Tôi về cơ bản đang tìm kiếm một lớp bao bọc có thể làm điều đó. Oh, và tôi cần một tập tin như đối tượng.

tôi nghĩ, tôi có thể viết một cái gì đó như:

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

Tuy nhiên, nó chỉ ra rằng điều này không làm việc và tôi đã thử các lớp khác nhau từ io module nhưng không thể có được nó làm việc. Tôi hài lòng với bất kỳ lớp bao bọc nào có hành vi mong muốn.

Trả lời

0

Tôi đã viết lớp trình bao bọc riêng của mình để giữ nguyên đoạn dữ liệu đầu tiên. Bằng cách này tôi có thể tìm kiếm lại từ đầu, phân tích mã hóa, loại tệp và những thứ khác. Lớp này giải quyết vấn đề cho tôi và nên đơn giản, đủ để thích ứng với các trường hợp sử dụng khác.

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. Bạn sử dụng 'readline()' có khả năng đọc toàn bộ câu trả lời nếu không có ngắt dòng trong đó. 2. Bạn nên kiểm tra xem kích thước của dữ liệu đã lưu ** cộng ** có phải kích thước của đường được lưu không vượt quá 'buffer_size' nếu không bạn có nguy cơ đệm nhiều hơn' buffer_size'. –

+0

@Piotr Dobrogost Cảm ơn bạn đã chỉ ra điều đó. Mã không hoàn chỉnh và chắc chắn không an toàn. Nó thiếu read() và cũng không hỗ trợ phản hồi từ mô-đun yêu cầu. Tuy nhiên, nó phục vụ mục đích. – dominik

0

Sử dụng Requests thư viện bạn có thể duyệt qua phản ứng mà đang được streamed:

Để sử dụng API Twitter phát trực tuyến để theo dõi từ khóa “yêu cầu”:

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) 

Để có thể tìm kiếm bạn phải lưu dữ liệu bạn đã lặp lại (đọc).

+0

Điều đó không trả lời được câu hỏi của tôi vì không có hỗ trợ cho 'tìm kiếm' và trả lại tệp như đối tượng. – dominik

Các vấn đề liên quan