2009-03-20 2 views
9

У меня есть сервер web.py, который отвечает на различные запросы пользователей. Одна из этих запросов включает загрузку и анализ серии веб-страниц.Python: простая асинхронная загрузка содержимого URL-адреса?

Есть ли простой способ настроить механизм загрузки URL-адресов на основе async/callback в web.py? Низкое использование ресурсов особенно важно, поскольку каждый инициированный пользователем запрос может привести к загрузке нескольких страниц.

Поток будет выглядеть следующим образом:

запроса пользователя -> web.py -> Скачать 10 страниц в параллельных или асинхронно -> Анализ содержания, возвращение результатов

Я признаю, что Twisted бы хороший способ для этого, но я уже в web.py, поэтому меня особенно интересует то, что может поместиться в web.py.

ответ

2

Используйте async http client, который использует asynchat и asyncore. http://sourceforge.net/projects/asynchttp/files/asynchttp-production/asynchttp.py-1.0/asynchttp.py/download

+0

У меня есть несколько исправления ошибок для кода asynchttpclient. Я попробовал переслать автора, но он, похоже, не вокруг. Если вам нужны эти исправления, вы можете написать мне по электронной почте. Я также включил HTTP-конвейерную обработку запросов, что должно дать дополнительный импульс для многих небольших запросов. – dhruvbird

+0

Вы можете найти исправления ошибок и расширения для клиента asynchttp здесь: http://code.google.com/p/asynhttp/ – dhruvbird

0

Я не уверен, что понимаю ваш вопрос, поэтому я дам несколько частичных ответов для начала.

  • Если ваша проблема в том, что web.py будет необходимости загружать данные откуда-то и анализировать результаты, прежде чем ответить, и вы боитесь, запрос может тайм-аут, прежде чем результаты будут готовы, вы можете использовать Ajax, чтобы разделить работу вверх. Вернитесь немедленно со страницы контейнера (чтобы сохранить результаты) и немного javascript, чтобы опросить ранг для результатов, пока у клиента не будет их всех. Таким образом, клиент никогда не ждет сервер, хотя пользователю все равно придется ждать результатов.
  • Если ваша проблема связана с сервером, ожидающим, пока клиент получит результаты, я сомневаюсь, что это действительно будет проблемой. Ваши сетевые слои не должны требовать от вас ждать при записи
  • Если вы беспокоитесь о сервере ожидания, пока клиент загружает статический контент из других, либо Ajax или умное использование переадресаций должно решить вашу проблему
+0

Проблема с решением ajax - это междоменные ограничения. Я не могу захватить контент со страниц, которые не поступают с исходного сервера. Кстати, я не беспокоюсь о ожидании при записи в этом случае , но на самом деле это проблема, о которой не заботился сетевой уровень. – Parand

+0

@Parand - Нет, но вы можете настроить дешевый прокси-сервер passthru в своем домене и попросить их сделать это. – MarkusQ

0

Я не знаю, будет ли это работать, но похоже, что он может: EvServer: Python Asynchronous WSGI Server имеет web.py interface и может делать push-стиль кометы для клиента браузера.

Если это не так, возможно, вы можете использовать Concurrence HTTP client для асинхронной загрузки страниц и выяснить, как обслуживать их в браузере через ajax или комету.

0

В соответствии с ответом MarkusQ MochiKit - это хорошая библиотека JavaScript с надежными асинхронными методами, вдохновленными Twisted.

0

На самом деле вы можете интегрировать скрученные с web.py. Я не совсем уверен, как, как я это делал, только с джанго (используется с ним скрученный).

4

Одним из вариантов было бы разместить работу на очереди какой-то (вы можете использовать что-то Enterprisey как ActiveMQ с pyactivemq или STOMP в качестве соединителя или вы могли бы использовать что-нибудь легкое, как Kestrel, которое написано в Scala и говорит то же самое protocl как memcache, чтобы вы могли просто использовать клиент python memcache, чтобы поговорить с ним).

Как только у вас установлен механизм очередей, вы можете создать столько или несколько рабочих задач, которые подписаны на очередь, и выполнять фактическую загрузку по своему усмотрению. Вы даже можете заставить их жить на других машинах, чтобы они не мешали скорости обслуживания вашего сайта вообще. Когда рабочие завершены, они отправляют результаты обратно в базу данных или в другую очередь, где веб-сервер может их забрать.

Если вы не хотите управлять внешними рабочими процессами, вы можете сделать рабочие потоки в одном и том же процессе python, на котором запущен веб-сервер, но тогда, очевидно, это будет иметь больший потенциал для воздействия на производительность веб-страницы ,

2

Я только что построил сервис в скрученном состоянии, который сделал эту параллельную выборку и анализ и доступ к ней из web.py в качестве простого HTTP-запроса.

3

Вы можете быть в состоянии использовать urllib для загрузки файлов и Queue модуля для управления числом рабочих потоков. например:

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

Вот интересный фрагмент кода. Я не использовал его сам, но это выглядит красиво;)

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

Низкий уровень AsyncHTTPClient:

"неблокирующая клиент HTTP поддерживается с pycurl Пример использования:".

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() 

" выборки() может принять строку URL или экземпляр HTTPRequest, который предлагает больше вариантов, как выполнение запросов POST/PUT/DELETE.

Ключевой аргумент max_clients для конструктора AsyncHTTPClient определяет максимальное количество одновременных операций fetch(), которые могут выполняться параллельно на каждом IOLoop. «

Существует также новая реализация в процессе: https://github.com/facebook/tornado/blob/master/tornado/simple_httpclient.py » Неблокирующая HTTP-клиент без каких-либо внешних зависимостей. ... Этот класс еще находится в разработке и пока не рекомендуется для использования в производстве «

2

В настоящее время существует отличный Python ЛИЭС вы можете захотеть использовать -. urllib3 (используют пулы) и requests (использует пулы потоков через urllib3 или неиспользованию блокировка IO до gevent)

Смежные вопросы