我正在使用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个网址。在这种情况下,当异常触发时,我将丢失有关已爬网页面的信息。
问题是 - 即使Timeout发生,我如何保存状态并处理数据?
答案 0 :(得分: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的dict或其他内容中保存状态,或者在不同的数组中附加失败的状态,以便稍后重试。
答案 1 :(得分: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源代码,每个源代码都在独立请求中检索。如果其中一个请求超时,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
不应该太高。