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

Python:url内容的简单异步下载?,python,asynchronous,Python,Asynchronous,我有一个web.py服务器,可以响应各种用户请求。其中一个请求涉及下载和分析一系列网页 有没有一种简单的方法可以在web.py中设置基于异步/回调的url下载机制?低资源使用率尤其重要,因为每个用户发起的请求都可能导致下载多个页面 流程如下所示: 用户请求->web.py->并行或异步下载10页->分析内容,返回结果 我知道Twisted是一个很好的方法,但是我已经在web.py中了,所以我特别感兴趣的是可以放在web.py中的东西。我不确定我是否理解您的问题,所以我首先给出多个部分答案 如果

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

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

流程如下所示:

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


我知道Twisted是一个很好的方法,但是我已经在web.py中了,所以我特别感兴趣的是可以放在web.py中的东西。

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

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

我不知道这是否确实有效,但它看起来可能会:有一个comet风格的推送到浏览器客户端


如果这不正确,也许您可以使用异步下载页面,并了解如何通过ajax或comet将其提供给浏览器。

按照MarkusQ的回答,这是一个很好的JavaScript库,具有受Twisted启发的健壮异步方法。

实际上您可以将Twisted与web.py集成。我真的不知道怎么做,因为我只使用django(与它一起使用twisted)。

一个选项是将工作发布到某种队列上(您可以使用Enterprisey之类的东西作为连接器,也可以使用Scala编写的轻量级东西,它与memcache使用相同的协议,这样您就可以使用python memcache客户端与它进行通信)

一旦设置了排队机制,您就可以创建订阅到队列中的任意多个或任意少的辅助任务,并根据需要执行实际下载工作。您甚至可以让它们在其他机器上运行,这样它们就不会干扰网站的服务速度。辅助任务完成后,它们会将结果发布回您的网站Web服务器可以在其中拾取它们的数据库或其他队列


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

我只想在twisted中构建一个服务,该服务可以执行并发获取和分析以及作为一个简单的http请求从web.py访问。

使用使用asynchat和asyncore的异步http客户端。

您可以使用下载文件和模块来管理多个工作线程。例如:

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

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

低级异步HttpClient:

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

" fetch()可以采用字符串URL或HTTPRequest实例,后者提供了更多选项,如执行POST/PUT/DELETE请求

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

还有新的实施工作正在进行中:
“无外部依赖项的非阻塞HTTP客户端……此类仍在开发中,尚未推荐用于生产。”

如今,您可能需要使用一些优秀的Python LIB—(使用线程池)和(通过urllib3使用线程池或通过非阻塞IO使用线程池)

ajax解决方案的问题是跨域限制-我无法从非源服务器的页面中获取内容。顺便说一句,在这种情况下,我不担心等待写入,但这实际上是一个网络层没有考虑的问题。@Parand--不,但是你可以在你的域中设置一个便宜的passthru代理,让他们完成它。我对asynchttpclient代码进行了一些错误修复。我试着给作者发邮件,但他似乎不在。如果你想要这些修复,你可以给我发电子邮件。此外,我还启用了HTTP请求管道,这将进一步提高许多小型请求的速度。您可以在这里找到asynchttp客户端的错误修复和扩展:有点离题(用线程而不是aio来回避问题),但这可能是一条路;)您可以使用wait asyncio.get_event_loop().run_in_executor(executor,您的_blocking_callable,*args)与线程/队列接口
asyncio
,并将可调用的同步消息传递给它。
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()