2013-04-17 9 views
6

Biorąc pod uwagę standard urllib.request obiekt, pobierane tak:urllib.request: jakikolwiek sposób na odczytanie z niego bez modyfikowania obiektu żądania?

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

Jeśli czytam jego zawartości poprzez req.read(), potem obiekt żądania będzie pusta.

Jednak w przeciwieństwie do zwykłych obiektów podobnych do plików, obiekt żądania nie ma metody seek, ponieważ jestem pewien, że są to doskonałe powody.

Jednak w moim przypadku mam funkcję i chcę, aby to ona ustaliła pewne żądania, a następnie zwróciła tę prośbę "bez szwanku", aby można ją było ponownie przeczytać.

Rozumiem, że jedną z opcji jest jej ponowne przesłanie. Ale chciałbym móc uniknąć tworzenia wielu żądań HTTP dla tego samego adresu url &.

Jedyną alternatywą, o której mogę pomyśleć, to przywrócenie funkcji zwracanej krotki wyodrębnionej treści i obiektu żądania, przy założeniu, że wszystko, co wywołuje tę funkcję, będzie wymagało pobrania treści w ten sposób.

Czy to moja jedyna opcja?

+1

Nie używaj 'urllib.urlopen' - [* Zauważ również, że funkcja urllib.urlopen() została usunięta w Pythonie 3 na rzecz urllib2.urlopen() *] (http: //docs.python. org/2/library/urllib.html) –

+0

Dzięki za poinformowanie mnie, chociaż w tym przypadku zachowanie z 'urllib2.urlopen' jest takie samo. –

Odpowiedz

3

Delegat buforowanie do StringIO obiektu (kod nie testowane, tak aby dać pomysł):

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) 

Jeśli kod faktycznie spodziewa prawdziwy Request obiektu (tj wzywa isinstance aby sprawdzić typ), a następnie podklasa Request i nie musisz nawet implementować __getattr__.

Należy zauważyć, że jest możliwe, że funkcja sprawdza dokładnie klasę (iw tym przypadku nie można nic zrobić) lub, jeśli jest napisana w języku C, wywołuje metodę za pomocą wywołań C/API (w takim przypadku nadpisywana metoda nie będzie wywoływana).

+0

Czy nie powinieneś ustawić 'self._content' jako coś w rodzaju' StringIO' zamiast 'None'? Na pewno pobiegniesz do 'AttributeError' podczas wywoływania' write'. –

+1

@JordanReiter Przepraszamy. Na początku napisałem 'self._content = StringIO()' następnie zmieniłem zdanie i zapomniałem naprawić ten fragment kodu, który zakładał, że 'self._content' został już zainicjowany. – Bakuriu

2

Utwórz podklasę o nazwie urllib2.Request, która korzysta z cStringIO.StringIO do przechowywania wszystkiego, co zostanie odczytane. Następnie możesz wdrożyć seek i tak dalej. Właściwie możesz po prostu użyć łańcucha, ale to będzie więcej pracy.

Powiązane problemy