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

3

我希望能够快速地抓取一个URL并在流式处理时解析它。最好是非常快的。我选择的编程语言是Python。我有一种直觉,认为Twisted可以做到这一点,但我无法找到一个例子。

2个回答

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

0

你只需要解析单个URL吗?那就不用担心。使用urllib2打开连接并将文件句柄传递给ElementTree。

你可以尝试使用ElementTree的增量解析器或使用iterparse进行变化,但这取决于你的实际需求。有“超级快速”的解析方法,但也有“足够快”的解析方法。

只有当你开始同时拥有多个连接时,才应该考虑Twisted或多线程。


我正在每60秒从一个80兆字节的XML流更新一个SQLite数据库,如果我能在整个过程完成之前流式传输XML、解析它并更新数据库,那就太棒了!也许我有点过于乐观了,但似乎Twisted应该能够帮助我解决这个问题。 - Influx
就像我说的,你只有一个输入流。Twisted不会有任何影响。如果你只需要从XML流中获取一点数据,你可以直接编写SAX处理程序,这可能会很繁琐,但在Python代码中速度大致相同。试试看。如果它能正常工作 - 你就完成了!根据http://codespeak.net/lxml/performance.html的数据,你应该能够读取至少3MB/秒,因此能够在30秒内解析该文件。 - Andrew Dalke
我认为我读取了错误的时间信息。看起来在现代机器上解析一个3MB的文件需要0.14秒,对于一个测试用例,因此80MB应该在5秒内完成。就像我说的,你可以自己测试一下时间。 - Andrew Dalke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接