Wenn ich diese Art von Fehlern zuvor behandelt habe, habe ich einen Dekorator geschrieben, der den Funktionsaufruf eine bestimmte Anzahl von Wiederholungen wiederholt, wenn eine bestimmte Ausnahme ausgelöst wird.
from functools import wraps
import time
from requests.exceptions import RequestException
from socket import timeout
class Retry(object):
"""Decorator that retries a function call a number of times, optionally
with particular exceptions triggering a retry, whereas unlisted exceptions
are raised.
:param pause: Number of seconds to pause before retrying
:param retreat: Factor by which to extend pause time each retry
:param max_pause: Maximum time to pause before retry. Overrides pause times
calculated by retreat.
:param cleanup: Function to run if all retries fail. Takes the same
arguments as the decorated function.
"""
def __init__(self, times, exceptions=(IndexError), pause=1, retreat=1,
max_pause=None, cleanup=None):
"""Initiliase all input params"""
self.times = times
self.exceptions = exceptions
self.pause = pause
self.retreat = retreat
self.max_pause = max_pause or (pause * retreat ** times)
self.cleanup = cleanup
def __call__(self, f):
"""
A decorator function to retry a function (ie API call, web query) a
number of times, with optional exceptions under which to retry.
Returns results of a cleanup function if all retries fail.
:return: decorator function.
"""
@wraps(f)
def wrapped_f(*args, **kwargs):
for i in range(self.times):
# Exponential backoff if required and limit to a max pause time
pause = min(self.pause * self.retreat ** i, self.max_pause)
try:
return f(*args, **kwargs)
except self.exceptions:
if self.pause is not None:
time.sleep(pause)
else:
pass
if self.cleanup is not None:
return self.cleanup(*args, **kwargs)
return wrapped_f
Sie eine Funktion machen kann mit einem gescheiterten Anruf behandeln (nach max Wiederholungen):
def failed_call(*args, **kwargs):
"""Deal with a failed call within various web service calls.
Will print to a log file with details of failed call.
"""
print("Failed call: " + str(args) + str(kwargs))
# Don't have to raise this here if you don't want to.
# Would be used if you want to do some other try/except error catching.
raise RequestException
eine Klasseninstanz Machen Sie Ihre Funktion dekorieren ruft:
#Class instance to use as a retry decorator
retry = Retry(times=5, pause=1, retreat=2, cleanup=failed_call,
exceptions=(RequestException, timeout))
Mit retreat=2
, die erste Wiederholung wird nach 1 Sekunde, die zweite Wiederholung nach 2 Sekunden, die dritte nach 4 Sekunden usw.
passieren 210
und definieren Sie Ihre Funktion eine Website, dekoriert mit Ihrem Wiederholungs Dekorateur zu kratzen:
@retry
def scrape_a_site(url, params):
r = requests.get(url, params=params)
return r
Beachten Sie, dass Sie leicht, welche Ausnahmen auslösen wird eine Wiederholung einstellen. Ich habe RequestException
und timeout
hier verwendet. Passen Sie sich Ihrer Situation an.
In Bezug auf den Code, können Sie es zu so etwas wie dies anpassen konnte (Ihr Dekorateur mit dem ersten Codeblock oben definiert haben):
#Class instance to use as a retry decorator
retry = Retry(times=5, pause=1, retreat=2, cleanup=None,
exceptions=(RequestException, timeout))
@retry
def get_html(browser, url):
'''Get HTML from url'''
browser.get(url)
return browser.page_source
def scrape(urls):
browser = webdriver.Firefox()
datatable=[]
for url in urls:
html = get_html(browser, url)
soup=BeautifulSoup(html,"html.parser")
table = soup.find('table', { "class" : "table table-condensed table-hover data-table m-n-t-15" })
Beachten Sie, dass @retry
auf den kleinsten Block anwenden von Code kann man (nur die Web-Lookup-Logik).
Manchmal hatte der Server ein Zeitlimit von 30 Sekunden, was bedeutet, dass Ihr Skript beendet wird, wenn es nicht innerhalb der Zeitbegrenzung abgeschlossen wird. Wenn das der Grund ist, können Sie dieses Kratzen auf der Hintergrundaufgabe mit Sellerie verwenden. –
Ich habe nie Sellerie verwendet, und plus ich bin total Anfänger in Linux + in Python, also wahrscheinlich, wenn ich es mit try-except-Methode nicht lösen kann, ich öffne nur das Skript mit einem Job-Scheduling (Crom) –