2009-03-20 12 views
9

Ho un server web.py che risponde a varie richieste dell'utente. Una di queste richieste comporta il download e l'analisi di una serie di pagine Web.Python: semplice download asincrono del contenuto dell'URL?

C'è un modo semplice per configurare un meccanismo di download url async/callback basato su web.py? L'utilizzo limitato delle risorse è particolarmente importante in quanto ogni richiesta avviata dall'utente potrebbe comportare il download di più pagine.

Il flusso sarà simile:

richiesta utente -> web.py -> Scarica 10 pagine in parallelo o in modo asincrono - contenuti> Analizzare, restituire risultati

riconosco che ritorto sarebbe un bel modo per fare questo, ma io sono già in web.py quindi sono particolarmente interessato a qualcosa che possa adattarsi a web.py.

risposta

2
+0

Ho alcuni correzioni di errori al codice asynchttpclient. Ho provato a spedire l'autore, ma lui non sembra essere nei paraggi. Se vuoi quelle correzioni, puoi scrivermi. Ho anche abilitato il pipelining della richiesta HTTP, che dovrebbe dare un ulteriore impulso alla velocità per molte richieste piccole. – dhruvbird

+0

Puoi trovare le correzioni dei bug e le estensioni al client asynchttp qui: http://code.google.com/p/asynhttp/ – dhruvbird

0

Non sono sicuro di comprendere la tua domanda, quindi darò più risposte parziali per iniziare.

  • Se la vostra preoccupazione è che web.py sta avendo per scaricare i dati da qualche parte e analizzare i risultati prima di rispondere e si teme la richiesta può timeout prima che i risultati sono pronti, si potrebbe usare Ajax per dividere il lavoro su. Ritorna immediatamente con una pagina del contenitore (per contenere i risultati) e un po 'di javascript per interrogare il sever per i risultati finché il client non li ha tutti. Pertanto, il client non attende mai il server, sebbene l'utente debba ancora attendere i risultati.
  • Se il problema riguarda il server in attesa che il client ottenga i risultati, dubito che sarà effettivamente un problema. I suoi strati di rete non dovrebbero richiedere di aspettare-on-write
  • Se siete preoccuparsi il server in attesa mentre il client scarica contenuti statici da altrove, sia ajax o l'uso intelligente di redirect dovrebbe risolvere il tuo problema
+0

Il problema con la soluzione ajax è le restrizioni di dominio: non riesco ad afferrare il contenuto da pagine che non provengono dal server di origine. Btw, non sono preoccupato di aspettare per scrivere in questo caso , ma questo in realtà è un problema non risolto dal livello di rete – Parand

+0

@Parand - No, ma è possibile impostare un proxy passthru a basso costo nel proprio dominio e farli passare attraverso quello – MarkusQ

0

Lungo la linea della risposta di MarkusQ, MochiKit è una bella libreria JavaScript, con robusti metodi asincroni ispirati a Twisted.

0

In realtà è possibile integrare twistato con web.py. Non sono davvero sicuro di come l'ho fatto solo con il django (usato contorto con esso).

4

Una possibilità potrebbe essere quella di inviare il lavoro su una coda di qualche tipo (si potrebbe usare qualcosa enterprisey come ActiveMQ con pyactivemq o STOMP come un connettore o si potrebbe usare qualcosa di leggero come Kestrel che è scritto in Scala e parla la stessa protocl come memcache in modo che tu possa semplicemente usare il client python memcache per parlarci).

Una volta impostato il meccanismo di accodamento, è possibile creare tutte le attività di lavoro che sono state sottoscritte alla coda e eseguire il lavoro di download come desiderato. Puoi persino farli vivere su altre macchine in modo che non interferiscano con la velocità di servire il tuo sito web. Quando i dipendenti hanno finito, pubblicano i risultati sul database o su un'altra coda in cui il webserver può prelevarli.

Se non si desidera gestire i processi di lavoro esterni, è possibile creare i thread di lavoro nello stesso processo Python che esegue il server Web, ma ovviamente avrà un maggiore potenziale di impatto sul rendimento delle pagine Web in uso .

2

Mi piacerebbe solo creare un servizio in twisted che eseguisse il recupero e l'analisi simultanei e accedessi da web.py come una semplice richiesta http.

3

Potreste essere in grado di utilizzare urllib per scaricare i file e il modulo Queue di gestire un numero di thread di lavoro. ad esempio:

import urllib 
from threading import Thread 
from Queue import Queue 

NUM_WORKERS = 20 

class Dnld: 
    def __init__(self): 
     self.Q = Queue() 
     for i in xrange(NUM_WORKERS): 
      t = Thread(target=self.worker) 
      t.setDaemon(True) 
      t.start() 

    def worker(self): 
     while 1: 
      url, Q = self.Q.get() 
      try: 
       f = urllib.urlopen(url) 
       Q.put(('ok', url, f.read())) 
       f.close() 
      except Exception, e: 
       Q.put(('error', url, e)) 
       try: f.close() # clean up 
       except: pass 

    def download_urls(self, L): 
     Q = Queue() # Create a second queue so the worker 
        # threads can send the data back again 
     for url in L: 
      # Add the URLs in `L` to be downloaded asynchronously 
      self.Q.put((url, Q)) 

     rtn = [] 
     for i in xrange(len(L)): 
      # Get the data as it arrives, raising 
      # any exceptions if they occur 
      status, url, data = Q.get() 
      if status == 'ok': 
       rtn.append((url, data)) 
      else: 
       raise data 
     return rtn 

inst = Dnld() 
for url, data in inst.download_urls(['http://www.google.com']*2): 
    print url, data 
6

Ecco un pezzo di codice interessante. Non ho usato io stesso, ma sembra bello;)

https://github.com/facebook/tornado/blob/master/tornado/httpclient.py

Basso livello AsyncHTTPClient:

"Un client HTTP non-blocking sostenuto con pycurl Esempio di utilizzo:."

import ioloop 

def handle_request(response): 
    if response.error: 
     print "Error:", response.error 
    else: 
     print response.body 
    ioloop.IOLoop.instance().stop() 

http_client = httpclient.AsyncHTTPClient() 
http_client.fetch("http://www.google.com/", handle_request) 
ioloop.IOLoop.instance().start() 

" fetch() può prendere un URL stringa o un'istanza HTTPRequest, che offre più opzioni, come l'esecuzione di POST/PUT/DELETE richieste.

L'argomento della parola chiave max_clients al costruttore AsyncHTTPClient determina il numero massimo di operazioni fetch() simultanee che possono essere eseguite in parallelo su ciascun IOLoop. "

C'è anche nuova implementazione in corso: https://github.com/facebook/tornado/blob/master/tornado/simple_httpclient.py " non bloccante client HTTP senza dipendenze esterne. ... Questa classe è ancora in sviluppo e non ancora raccomandato per l'uso produzione "

2

Al giorno d'oggi ci sono ottime librerie Python si potrebbe desiderare di utilizzare -. urllib3 (utilizza pool di thread) e requests (utilizza pool di thread attraverso urllib3 o non blocco da IO a

Problemi correlati