Python:url内容的简单异步下载?

时间:2009-03-20 22:40:42

标签: python asynchronous

我有一个响应各种用户请求的web.py服务器。其中一个请求涉及下载和分析一系列网页。

有没有一种简单的方法在web.py中设置基于异步/回调的url下载机制?资源使用率低是特别重要的,因为每个用户发起的请求都可能导致下载多个页面。

流程看起来像:

用户请求 - > web.py - >并行或异步下载10页 - >分析内容,返回结果

我认识到Twisted是一个很好的方法,但我已经在web.py中了,所以我对web.py中的内容特别感兴趣。

10 个答案:

答案 0 :(得分:6)

这是一段有趣的代码。我自己没有使用它,但它看起来不错;)

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

低级AsyncHTTPClient:

“使用pycurl支持的非阻塞HTTP客户端。示例用法:”

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()可以使用字符串URL或HTTPRequest实例,它提供了更多选项,例如执行POST / PUT / DELETE请求。

AsyncHTTPClient构造函数的关键字参数max_clients确定可以在每个IOLoop上并行执行的最大并发fetch()操作数。 “

还有新的实施正在进行中: https://github.com/facebook/tornado/blob/master/tornado/simple_httpclient.py “没有外部依赖关系的非阻塞HTTP客户端。...此类仍在开发中,尚未推荐用于生产。”

答案 1 :(得分:4)

一种选择是将作品发布到某种类型的队列中(您可以使用像ActiveMQ那样pyactivemqSTOMP作为连接器的东西,或者您可以使用轻量级的东西比如Kestrel,它是用Scala编写的,与memcache说的是同一个protocl,所以你可以使用python memcache客户端与它交谈。)

设置排队机制后,您可以创建订阅队列的任意数量的工作任务,并根据需要执行实际的下载工作。您甚至可以让它们在其他机器上运行,这样它们就不会干扰为您的网站提供服务的速度。当工作人员完成后,他们会将结果发布回数据库或网络服务器可以接收的其他队列。

如果您不想管理外部工作进程,那么您可以在运行Web服务器的同一个python进程中创建工作线程,但显然它会更有可能影响您的网页服务性能。

答案 2 :(得分:3)

您可以使用urllib下载文件,使用Queue模块来管理多个工作线程。 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

答案 3 :(得分:2)

我只是在twisted中构建一个服务,进行并发获取和分析,并从web.py访问它作为一个简单的http请求。

答案 4 :(得分:2)

答案 5 :(得分:2)

现在你可能想要使用优秀的Python库 - urllib3(使用线程池)和requests(通过urllib3使用线程池或通过gevent使用非阻塞IO)

答案 6 :(得分:0)

我不确定我是否理解你的问题,所以我会先给出多个部分答案。

  • 如果您担心web.py必须从某个地方下载数据并在响应之前分析结果,并且您担心请求可能在结果准备好之前超时,您可以使用ajax来分解工作。立即返回一个容器页面(保存结果)和一些javascript来轮询服务器以获得结果,直到客户端拥有它们。因此,客户端永远不会等待服务器,但用户仍然必须等待结果。
  • 如果您担心服务器正在等待客户端获得结果,我怀疑这是否真的会成为问题。您的网络层不应要求您等待写入
  • 如果您担心服务器等待客户端从其他地方下载静态内容时,ajax或巧妙使用重定向应该可以解决您的问题

答案 7 :(得分:0)

我不知道这是否真的有效,但看起来可能如此:EvServer: Python Asynchronous WSGI Server有一个web.py interface,可以将彗星风格推送到浏览器客户端。

如果这不对,也许您可​​以使用Concurrence HTTP client进行页面的异步下载,并找出如何通过ajax或comet将它们提供给浏览器。

答案 8 :(得分:0)

根据MarkusQ的回答,MochiKit是一个不错的JavaScript库,具有受Twisted启发的强大的异步方法。

答案 9 :(得分:0)

实际上你可以将twisted与web.py集成在一起。我不太确定我是怎么用django做的(用过它来扭曲)。