2009-03-20 9 views
9

Tengo un servidor web.py que responde a varias solicitudes de los usuarios. Una de estas solicitudes implica la descarga y el análisis de una serie de páginas web.Python: descarga asincrónica simple del contenido de la url

¿Hay una manera simple de instalar un/a base de devolución de llamada mecanismo de dirección URL de descarga asíncrona en web.py? El bajo uso de recursos es particularmente importante, ya que cada solicitud iniciada por el usuario podría ocasionar la descarga de varias páginas.

El flujo se vería así:

petición del usuario -> web.py -> Descargar 10 páginas en paralelo o de forma asíncrona - contenidos> Analizar, resultados de retorno

que reconocen que Twisted sería una buena manera de para hacer esto, pero ya estoy en web.py, así que estoy particularmente interesado en algo que pueda encajar en web.py.

Respuesta

2
+0

Tengo algunos correcciones de errores al código asynchttpclient. Intenté enviar por correo al autor, pero él no parece estar cerca. Si quieres esas correcciones, puedes enviarme un correo electrónico. También he habilitado la canalización de solicitudes HTTP, lo que debería dar un impulso adicional a las velocidades para muchas solicitudes pequeñas. – dhruvbird

+0

Puede encontrar las correcciones de errores y extensiones para el cliente asynchttp aquí: http://code.google.com/p/asynhttp/ – dhruvbird

0

no estoy seguro de que estoy entender su pregunta, así que voy a dar múltiples respuestas parciales para empezar.

  • Si su preocupación es que web.py es tener que descargar los datos desde algún lugar y analizar los resultados antes de responder y temen la solicitud puede tiempo de espera antes de que los resultados estén listos, se puede usar Ajax para dividir el trabajo arriba. Regrese inmediatamente con una página de contenedor (para guardar los resultados) y un poco de javascript para sondear el servidor de los resultados hasta que el cliente los tenga todos. Por lo tanto, el cliente nunca espera al servidor, aunque el usuario aún debe esperar los resultados.
  • Si su preocupación es atar el servidor de espera para el cliente para obtener los resultados, dudo que va a ser realmente un problema. Sus capas de redes no deberían requerir que espere en escritura
  • Si están preocupados por el servidor en espera mientras el cliente descarga el contenido estático de otros lugares, ya sea ajax o un uso inteligente de redirecciones debe resolver su problema
+0

El problema con la solución ajax son las restricciones entre dominios - No puedo capturar el contenido de las páginas que no provienen del servidor de origen. Por cierto, no estoy preocupado por esperar a escribir en este caso , pero eso en realidad es un problema no atendido por la capa de red. – Parand

+0

@Parand - No, pero puede configurar un proxy de paso a bajo en su dominio y hacer que lo superen. – MarkusQ

0

En la línea de la respuesta de MarkusQ, MochiKit es una buena biblioteca de JavaScript, con robustos métodos asíncronos inspirados en Twisted.

0

En realidad se puede integrar con trenzado web.py. No estoy muy seguro de cómo lo he hecho con django (usado retorcido con él).

4

Una opción sería publicar el trabajo en una cola de algún tipo (que podría utilizar algo enterprisey como ActiveMQ con pyactivemq o STOMP como un conector o usted podría utilizar algo ligero como Kestrel que está escrito en Scala y habla el mismo protocl como memcache para que pueda usar el cliente de memcache de python para hablar con él).

vez que tenga el mecanismo de cola establecido, puede crear tantas o tan pocas tareas de los trabajadores que están suscritos a la cola y hacen el trabajo real de la descarga como desee. Incluso puede tenerlos en vivo en otras máquinas para que no interfieran con la velocidad de servicio de su sitio web. Cuando los trabajadores terminan, vuelven a publicar los resultados en la base de datos u otra fila donde el servidor web puede recogerlos.

Si no desea tener que gestionar los procesos de trabajo externos, puede crear los hilos de trabajo en el mismo proceso python que ejecuta el servidor web, pero obviamente tendrá un mayor potencial para afectar el rendimiento de la publicación de su página web. .

2

Acabo de construir un servicio en twisted que hizo esa búsqueda simultánea y el análisis y el acceso desde web.py como una simple solicitud http.

3

Usted puede ser capaz de utilizar urllib para descargar los archivos y el módulo Queue para gestionar un número de subprocesos de trabajo. e.g:

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

Aquí hay una pieza interesante de código. Yo no lo uso yo, pero se ve muy bien;)

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

bajo nivel AsyncHTTPClient:

"Un cliente HTTP no bloqueante respaldado con pycurl Ejemplo de uso:."

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() puede tomar una URL cadena o una instancia HTTPRequest, que ofrece más opciones, como la ejecución de POST/PUT/DELETE solicitudes.

El argumento de palabra clave max_clients para el constructor AsyncHTTPClient determina el número máximo de operaciones de búsqueda simultáneas() que se pueden ejecutar en paralelo en cada IOLoop. "

También hay nueva implementación en curso: https://github.com/facebook/tornado/blob/master/tornado/simple_httpclient.py " para no bloquear cliente HTTP sin dependencias externas. ... Esta clase está todavía en desarrollo y aún no se recomienda para su uso en producción "

2

Hoy en día hay excelentes librerías de Python es posible que desee utilizar -. urllib3 (utiliza conjuntos de subprocesos) y requests (utiliza agrupaciones de hebras a través urllib3 o no bloqueando IO a través de gevent)

Cuestiones relacionadas