如何用Python Twisted获取并解析XML文档?

3 投票
2 回答
1614 浏览
提问于 2025-04-15 15:35

我想要一种快速的方法来获取一个网址并在流式处理的同时解析它。理想情况下,这个过程应该非常快。我选择的编程语言是Python。我觉得twisted这个库可以做到这一点,但我找不到相关的例子。

2 个回答

0

你只需要处理一个网址吗?那就不用担心。可以用urllib2来打开连接,然后把文件句柄传给ElementTree。

你可以尝试一些不同的方法,比如使用ElementTree的增量解析器或者iterparse,但这要看你具体的需求是什么。有的方式是“超级快”,但也有“足够快”的选择。

只有当你需要同时处理多个连接时,才需要考虑使用Twisted或者多线程。

7

如果你需要以流式的方式处理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 会把响应的内容写入一个类似文件的对象中。这里,传入一个有 writeclose 方法的对象就满足了这个要求,但它会逐步解析数据为XML,而不是直接把它存到磁盘上。

另一种方法是直接在 HTTPPageGetter 的层面上进行操作。 HTTPPageGettergetPage 内部使用的协议。

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

最后,新的HTTP客户端API很快就会推出。因为这还不是正式发布的一部分,所以它没有前面两种方法那么直接好用,但它会更方便,所以我提到它,让你对未来有个了解。:) 新的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

撰写回答