Если вам нужно обрабатывать HTTP-ответы в потоковом режиме, есть несколько вариантов.
Вы можете сделать это через downloadPage
:
from xml.sax import make_parser
from twisted.web.client import downloadPage
class StreamingXMLParser:
def __init__(self):
self._parser = make_parser()
def write(self, bytes):
self._parser.feed(bytes)
def close(self):
self._parser.feed('', True)
parser = StreamingXMLParser()
d = downloadPage(url, parser)
# d fires when the response is completely received
Это работает, потому что downloadPage
записывает тело ответа в файлоподобный переданный ему объект. Здесь передача объекта с помощью методов write
и close
удовлетворяет этому требованию, но постепенно анализирует данные как XML, а не помещает их на диск.
Другой подход заключается в подключении к вещам на уровне HTTPPageGetter
. HTTPPageGetter
- это протокол, используемый внутренне getPage
.
class StreamingXMLParsingHTTPClient(HTTPPageGetter):
def connectionMade(self):
HTTPPageGetter.connectionMade(self)
self._parser = make_parser()
def handleResponsePart(self, bytes):
self._parser.feed(bytes)
def handleResponseEnd(self):
self._parser.feed('', True)
self.handleResponse(None) # Whatever you pass to handleResponse will be the result of the Deferred below.
factory = HTTPClientFactory(url)
factory.protocol = StreamingXMLParsingHTTPClient
reactor.connectTCP(host, port, factory)
d = factory.deferred
# d fires when the response is completely received
Наконец, скоро будет новый API-интерфейс клиента HTTP. Поскольку это еще не является частью какого-либо релиза, он не так непосредственно полезен, как предыдущие два подхода, но он несколько лучше, поэтому я включу его, чтобы дать вам представление о том, что принесет будущее. :) Новый API позволяет указать протокол для получения тела ответа. Итак, вы бы сделали что-то вроде этого:
class StreamingXMLParser(Protocol):
def __init__(self):
self.done = Deferred()
def connectionMade(self):
self._parser = make_parser()
def dataReceived(self, bytes):
self._parser.feed(bytes)
def connectionLost(self, reason):
self._parser.feed('', True)
self.done.callback(None)
from twisted.web.client import Agent
from twisted.internet import reactor
agent = Agent(reactor)
d = agent.request('GET', url, headers, None)
def cbRequest(response):
# You can look at the response headers here if you like.
protocol = StreamingXMLParser()
response.deliverBody(protocol)
return protocol.done
d.addCallback(cbRequest) # d fires when the response is fully received and parsed