2013-04-17 27 views
6

給定一個標準urllib.request對象,檢索,因此:urllib.request:以任何方式從它讀取而不修改請求對象?

req = urllib.urlopen('http://example.com') 

如果通過req.read()讀取其內容,然後請求對象將是空的。

但是,與普通的文件類對象不同,請求對象沒有seek方法,因爲我相信是很好的理由。

但是,在我的情況下,我有一個函數,我希望它對某個請求做出某些確定,然後將該請求「無損」返回,以便可以再次讀取該請求。

我知道一個選項是重新請求它。但我希望能夠避免對同一個網址發出多個HTTP請求。

我能想到的唯一另外一種選擇是讓函數返回提取內容和請求對象的元組,並明白任何調用此函數的東西都必須以這種方式獲取內容。

這是我唯一的選擇嗎?

+1

請勿使用'urllib.urlopen' - [*另請注意,urllib.urlopen()函數已在Python 3中被刪除,轉而使用urllib2.urlopen()*](http://docs.python。 org/2/library/urllib.html) –

+0

謝謝你讓我知道,儘管在這種情況下'urllib2.urlopen'的行爲是一樣的。 –

回答

3

代表緩存到StringIO對象(未測試的代碼,只是爲了讓這個想法):

import urllib 
from io import StringIO 


class CachedRequest(object): 
    def __init__(self, url): 
     self._request = urllib.urlopen(url) 
     self._content = None 

    def __getattr__(self, attr): 
     # if attr is not defined in CachedRequest, then get it from 
     # the request object. 
     return getattr(self._request, attr) 

    def read(self): 
     if self._content is None: 
      content = self._request.read() 
      self._content = StringIO() 
      self._content.write(content) 
      self._content.seek(0) 
      return content 
     else: 
      return self._content.read() 

    def seek(self, i): 
     self._content.seek(i) 

如果代碼實際上需要一個真正的Request對象(即調用isinstance檢查類型),那麼子Request,你甚至不需要執行__getattr__

請注意,函數可能會檢查確切的類(在這種情況下,您不能做任何事情),或者如果它用C語言編寫,則使用C/API調用調用方法(在這種情況下,重寫的方法不會被調用)。

+0

您不需要將'self._content'設置爲'StringIO'而不是'None'嗎?很確定,在調用'write'時,你會遇到'AttributeError'。 –

+1

@JordanReiter對不起。在開始時我寫了'self._content = StringIO()'然後我改變了主意,忘記修正假設'self._content'的代碼已經被初始化了。 – Bakuriu

2

創建一個urllib2.Request的子類,該子類使用cStringIO.StringIO來保存讀取的內容。然後你可以實現seek等等。其實你可以使用一個字符串,但那會更有用。