2009-11-02 6 views

Répondre

6

Si vous avez besoin de gérer les réponses HTTP en streaming, il existe quelques options.

Vous pouvez le faire via 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 

Cela fonctionne parce que le corps downloadPage écrit de réponse au -fichier objet qui lui est passé. Passer ici un objet avec les méthodes write et close satisfait à cette exigence, mais analyse les données de manière incrémentielle en XML au lieu de les placer sur un disque.

Une autre approche est de connecter les choses au niveau HTTPPageGetter. HTTPPageGetter est le protocole utilisé en interne par 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 

Enfin, il y aura une nouvelle API client HTTP bientôt. Comme cela ne fait partie d'aucune version, ce n'est pas aussi utile que les deux précédentes, mais c'est un peu plus joli, donc je vais l'inclure pour vous donner une idée de ce que l'avenir nous réserve. :) La nouvelle API vous permet de spécifier un protocole pour recevoir le corps de la réponse. Donc, vous feriez quelque chose comme ceci:

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

Vous avez seulement besoin d'analyser une seule URL? Alors ne t'inquiète pas. Utilisez urllib2 pour ouvrir la connexion et passez le handle de fichier dans ElementTree.

Les variations que vous pouvez essayer serait d'utiliser l'analyseur supplémentaire de ElementTree ou iterparse utiliser, mais cela dépend de ce que vos besoins réels sont. Il y a "super rapide" mais il y a aussi "assez vite".

Ce n'est que lorsque vous commencez à avoir plusieurs connexions simultanées que vous devriez regarder Twisted ou multithreading.

+0

Je met à jour une base de données SqlLite toutes les 60 secondes à partir d'un flux xml 80 méga-octets, si je pouvais diffuser le xml, analyser et mettre à jour la base de données avant la chose complète , ça serait génial! Peut-être que je suis un peu optimiste, mais il semble que Twisted devrait être en mesure de m'aider avec cela. – Influx

+0

Comme je l'ai dit, vous avez un seul flux d'entrée. Twisted ne fera pas un peu de différence. Si vous avez seulement besoin d'un peu de données du flux XML, vous pouvez écrire un gestionnaire SAX directement, ce qui sera fastidieux mais à peu près aussi rapide que vous pouvez obtenir en code Python. Essaye le. Si cela fonctionne, vous avez terminé! En regardant http://codespeak.net/lxml/performance.html vous devriez être capable de lire au moins 3MB/seconde afin d'être capable d'analyser ce fichier en 30 secondes. –

+0

Je pense que j'ai lu les informations de synchronisation erronées. Il semble qu'il faut 0,14s sur une machine moderne pour analyser un fichier de 3 Mo, pour un cas de test, donc 80 Mo devrait prendre moins de 5 secondes. Comme je l'ai dit, le temps pour vous. –

Questions connexes