2013-07-18 5 views
2

Я использую gevent для загрузки некоторых html-страниц. Некоторые веб-сайты являются слишком медленными, некоторые перестают обслуживать запросы после определенного периода времени. Вот почему мне пришлось ограничить общее время для группы запросов, которые я делаю. Для этого я использую gevent «Timeout».Правильное завершение зеленой линии

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-адресов прямо до того, как администраторы сайта решили переключить веб-сервер для обслуживания. В таком случае я потеряю информацию об обходных страницах при возникновении исключения.

Вопрос в том, как сохранить состояние и обработать данные, даже если время ожидания произойдет?

+0

Почему бы вам не задать один тайм-аут для каждого запроса? Что делает downloadUrl() на самом деле? Является ли это совместным блокированием? Можете ли вы предоставить самодостаточный пример? –

+0

Код упрощен. Функция downloadSite() содержит код, чтобы получить первую страницу, найти хорошие внутренние ссылки, загрузить их, найти дополнительные ссылки и т. д. ... Я не представляю, как обернуть каждый запрос в отдельный тайм-аут. Imho это неправильно с точки зрения программирования +, это создало бы существенное влияние на веб-сайт (Представьте, что вы одновременно запрашиваете 100 веб-страниц с сайта www.test.com) – 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

Спасибо, Габриэль, это работает. Я новичок в python и не знаю о «с» конструкцией :) – 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 раз HTML-код google.com, каждый из которых извлекается в независимом запросе. Если одно из запросов было вычислено, соответствующий элемент в contents будет None. Если у вас есть вопросы по этому коду, не стесняйтесь спрашивать в комментариях.

Я видел ваш последний комментарий. Определение одного тайм-аута для каждого запроса определенно не является неправильным с точки зрения программирования. Если вам нужно затормозить трафик на веб-сайт, то просто не создавайте 100 особей одновременно. Spawn 5, подождите, пока они не вернутся. Затем вы можете подождать определенное количество времени и развернуть следующие 5 (уже показано в другом ответе Габриэля Самфиры, как я вижу сейчас). Для моего кода выше, это будет означать, что вам придется неоднократно называть

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

Спасибо Ян-Филип! Я принял ответ Габриэля просто потому, что первым упомянул «с тайм-аутом (10):« построить, хотя код в основном похож. Еще раз спасибо) – Termos