2009-09-02 8 views
7

Je voudrais lire un site Web de manière asynchrone, ce qui n'est pas possible avec urllib autant que je sache. Maintenant, j'ai essayé de lire avec des prises simples, mais HTTP me donne l'enfer. Je cours dans tous les types d'encodages funky, par exemple l'encodage de transfert: chunked, j'ai besoin d'analyser tous ces trucs manuellement, et j'ai envie de coder C, pas python pour le moment.Lire un site Web avec asyncore

Y a-t-il une manière plus agréable comme URLLib, asynchrone? Je n'ai vraiment pas envie de ré-implémenter toute la spécification HTTP, quand tout a déjà été fait.

Twisted n'est pas une option actuellement.

Salutations,

Tom

Répondre

5

Avez-vous regardé http://asynchttp.sourceforge.net/?

« Client Asynchronous HTTP pour Python

Le module 'AsyncHTTP' » est une extension logique de la bibliothèque Python 'asynchat' module qui est construit sur les modules 'asyncore' et 'select'. Notre objectif est de fournir la fonctionnalité de l'excellent module 'httplib' sans utiliser de douilles de blocage. "

Le dernier commit du projet était le 2001-05-29, il semble donc mort. Mais cela pourrait être intéressant de toute façon.

Avis de non-responsabilité: Je ne l'ai pas utilisé moi-même.

En outre, this blog post a quelques informations sur HTTP asynchrone.

7

Vous pouvez mettre en œuvre un asynchrone vous appeler. Pour chaque appel, démarrez un nouveau thread (ou essayez d'en obtenir un dans un pool) et utilisez un callback pour le traiter.

Vous pouvez le faire très bien avec un décorateur:

def threaded(callback=lambda *args, **kwargs: None, daemonic=False): 
    """Decorate a function to run in its own thread and report the result 
    by calling callback with it.""" 
    def innerDecorator(func): 
     def inner(*args, **kwargs): 
      target = lambda: callback(func(*args, **kwargs)) 
      t = threading.Thread(target=target) 
      t.setDaemon(daemonic) 
      t.start() 
     return inner 
    return innerDecorator 

@threaded() 
def get_webpage(url): 
    data = urllib.urlopen(url).read() 
    print data 
+2

Désolé, comme je l'ai dit, je veux des prises asynchrones, pas fils. – Tom

+1

Suis-je la seule personne qui pense que cette solution est * brillante *?Ce qui rend les méthodes HTTP asynchrones * meilleures que toutes les autres * async est qu'il s'agit en fait d'une solution asynchrone totalement générale à * n'importe quoi *. Vous pouvez remplacer 'get_webpage' par n'importe quel code et le faire de façon asynchrone. – robru

1

Le plus loin que je suis venu utilisait asynchttp modifié, que codeape suggéré. J'ai essayé d'utiliser à la fois asyncore/asynchat et asynchttp, avec beaucoup de douleur. Il m'a fallu beaucoup trop de temps pour essayer de corriger tous les bugs dedans (il y a une méthode handle_read, presque copiée d'asyncore, seulement mal indentée et qui me donnait des maux de tête avec l'encodage en chunked). En outre, asyncore et asynchat ne sont pas mieux utilisés en fonction de quelques conseils que j'ai obtenus sur google.

Je me suis installé avec tordu, mais c'est évidemment hors de question pour vous. Cela peut aussi dépendre de ce que vous essayez de faire avec votre application et pourquoi vous voulez des requêtes asynchrones, si les threads sont une option ou non, si vous faites de la programmation graphique ou autre chose, donc si vous pouviez perdre plus d'information c'est toujours bon. Sinon, je voterais pour la version filetée proposée ci-dessus, elle offre beaucoup plus de lisibilité et de maintenabilité.

1

asyncore exemple simple client HTTP est assez simple :)

http://docs.python.org/library/asyncore.html

import asyncore, socket 

class HTTPClient(asyncore.dispatcher): 

    def __init__(self, host, path): 
     asyncore.dispatcher.__init__(self) 
     self.create_socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connect((host, 80)) 
     self.buffer = 'GET %s HTTP/1.0\r\n\r\n' % path 

    def handle_connect(self): 
     pass 

    def handle_close(self): 
     self.close() 

    def handle_read(self): 
     print self.recv(8192) 

    def writable(self): 
     return (len(self.buffer) > 0) 

    def handle_write(self): 
     sent = self.send(self.buffer) 
     self.buffer = self.buffer[sent:] 


client = HTTPClient('www.python.org', '/') 
asyncore.loop() 
Questions connexes