2013-07-18 35 views
2

我使用gevent下載一些html頁面。 有些網站速度太慢,一段時間後有些網站停止提供服務。這就是爲什麼我必須限制我提出的一組請求的總時間。爲此我使用gevent「超時」。正確的greenlet終止

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'。在網站管理員決定切換Web服務器進行維護之前,我已設法下載10個網址。在這種情況下,當異常情況發生時,我將丟失有關已爬網頁面的信息。

問題是 - 即使超時發生,我如何保存狀態並處理數據?

+0

爲什麼不定義每個請求一個超時? downloadUrl()實際上在做什麼?它是否合作阻止?你能提供一個獨立的例子嗎? –

+0

代碼被簡化。 downloadSite()函數包含獲取第一頁的代碼,找到良好的內部鏈接,下載它們,找到更多鏈接等等。我不會想象如何在單獨的Timeout中包裝每個請求。 Imho從編程的角度來看是錯誤的+它會對網站產生重大影響(想象一下從www.test.com中同時請求100個網頁) – Termos

回答

2

爲什麼不嘗試這樣的:

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,或追加在不同的陣列失敗的,後來重試。

+0

謝謝Gabriel,這是有效的。我是一個蟒蛇新手,不知道「與」構造:) – Termos

+0

很高興我可以幫助:) –

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。產卵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應該不會太高。

+0

謝謝Jan-Philip!我已經接受了加布裏埃爾的回答,僅僅是因爲第一個提到「用超時(10):」構造,儘管代碼基本相似。再次感謝) – Termos