Python:url内容的简单异步下载?
我有一个web.py服务器,可以响应各种用户请求。其中一个请求涉及下载和分析一系列网页 有没有一种简单的方法可以在web.py中设置基于异步/回调的url下载机制?低资源使用率尤其重要,因为每个用户发起的请求都可能导致下载多个页面 流程如下所示: 用户请求->web.py->并行或异步下载10页->分析内容,返回结果Python:url内容的简单异步下载?,python,asynchronous,Python,Asynchronous,我有一个web.py服务器,可以响应各种用户请求。其中一个请求涉及下载和分析一系列网页 有没有一种简单的方法可以在web.py中设置基于异步/回调的url下载机制?低资源使用率尤其重要,因为每个用户发起的请求都可能导致下载多个页面 流程如下所示: 用户请求->web.py->并行或异步下载10页->分析内容,返回结果 我知道Twisted是一个很好的方法,但是我已经在web.py中了,所以我特别感兴趣的是可以放在web.py中的东西。我不确定我是否理解您的问题,所以我首先给出多个部分答案 如果
我知道Twisted是一个很好的方法,但是我已经在web.py中了,所以我特别感兴趣的是可以放在web.py中的东西。我不确定我是否理解您的问题,所以我首先给出多个部分答案
- 如果您担心web.py必须从某处下载数据并在响应之前分析结果,并且您担心请求可能在结果准备好之前超时,那么您可以使用ajax来分割工作。立即返回一个容器页面(用来保存结果)和一点javascript来轮询服务器的结果,直到客户端拥有所有结果。因此,客户机从不等待服务器,尽管用户仍然需要等待结果
- 如果您担心的是占用服务器等待客户端获得结果,我怀疑这是否真的会是一个问题。您的网络层不应要求您等待写入
- 如果您担心客户端从其他地方下载静态内容时服务器会等待,那么ajax或巧妙地使用重定向应该可以解决您的问题
如果这不正确,也许您可以使用异步下载页面,并了解如何通过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()