4

我正在使用 gevent 下载一些 html 页面。有些网站太慢了,有些网站在一段时间后停止服务请求。这就是为什么我必须限制我提出的一组请求的总时间。为此,我使用 gevent“超时”。

timeout = Timeout(10)
timeout.start()

def downloadSite():
    # code to download site's url one by one
    url1 = downloadUrl()
    url2 = downloadUrl()
    url3 = downloadUrl()
try:
    gevent.spawn(downloadSite).join()
except Timeout:
    print 'Lost state here'

但它的问题是当异常触发时我会失去所有状态。

想象一下我抓取网站“www.test.com”。在站点管理员决定切换网络服务器进行维护之前,我已经设法下载了 10 个 URL。在这种情况下,当异常触发时,我将丢失有关已抓取页面的信息。

问题是 - 即使发生超时,我如何保存状态和处理数据?

4

2 回答 2

3

为什么不尝试类似的东西:

timeout = Timeout(10)

def downloadSite(url):
    with Timeout(10):
        downloadUrl(url)

urls = ["url1", "url2", "url3"]

workers = []
limit = 5
counter = 0
for i in urls:
    # limit to 5 URL requests at a time
    if counter < limit:
        workers.append(gevent.spawn(downloadSite, i))
        counter += 1
    else:
        gevent.joinall(workers)
        workers = [i,]
        counter = 0
gevent.joinall(workers)

您还可以将状态保存在字典或每个 URL 的其他内容中,或者将失败的状态附加到不同的数组中,以便稍后重试。

于 2013-07-18T13:05:21.123 回答
2

一个独立的例子:

import gevent
from gevent import monkey
from gevent import Timeout

gevent.monkey.patch_all()
import urllib2

def get_source(url):
    req = urllib2.Request(url)
    data = None
    with Timeout(2):
        response = urllib2.urlopen(req)
        data = response.read()
    return data

N = 10
urls = ['http://google.com' for _ in xrange(N)]
getlets = [gevent.spawn(get_source, url) for url in urls]
gevent.joinall(getlets)
contents = [g.get() for g in getlets]

print contents[5]

它为每个请求实现一个超时。在此示例中,contents包含 10 倍于 google.com 的 HTML 源,每个都在一个独立的请求中检索。如果其中一个请求已超时,则 in 中的相应元素contents将为None. 如果您对此代码有任何疑问,请随时在评论中提问。

我看到了你最后的评论。从编程的角度来看,为每个请求定义一个超时绝对没有错。如果您需要限制网站的流量,那么不要同时生成 100 个 greenlet。Spawn 5,等他们回来。然后,您可以等待给定的时间,然后生成下一个 5(如我现在所见,Gabriel Samfira 的另一个答案已经显示)。对于我上面的代码,这意味着您必须反复调用

N = 10
urls = ['http://google.com' for _ in xrange(N)]
getlets = [gevent.spawn(get_source, url) for url in urls]
gevent.joinall(getlets)
contents = [g.get() for g in getlets]

而不N应该太高。

于 2013-07-18T13:16:40.757 回答