2017-09-20 7 views
0

Ich habe ein Web-Verschrottungsskript, das auf Tausenden Verbindungen arbeitet. Aber manchmal bekomme ich Verbindungsfehler, Timeout-Fehler, schlechte Gateway Fehler und mein Skript stoppen ist nur ..Verbindungsfehler, Zeitüberschreitung, wenn ich Web-Verschrottung mit Python auf debian

Hier Code meinen Teil (in den URLs i Links haben, die, die ich mit einer Schleife laufen):

def scrape(urls): 
    browser = webdriver.Firefox() 
    datatable=[] 
    for url in urls: 
     browser.get(url) 
     html = browser.page_source 
     soup=BeautifulSoup(html,"html.parser") 
     table = soup.find('table', { "class" : "table table-condensed table-hover data-table m-n-t-15" }) 

Ich denke, ich muss eine Try-Catch-Methode verwenden, um es zu vermeiden, und wenn es passiert, versuchen Sie erneut, diese Website zu lesen.

Meine Frage ist, wo und was ich in meinen Code einbauen muss, um diese Fehler zu erkennen und es erneut zu versuchen/zum nächsten Link zu gehen?

try: 
    r = requests.get(url, params={'s': thing}) 
except requests.exceptions.RequestException: 
    # what i have to write plus and where i have to place correctly this part? 

Vielen Dank!

+0

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. –

+0

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) –

Antwort

1

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).

+0

Woah, es ist sehr komplex Beitrag, danke! Können Sie es hinzufügen und wie es in meinem Code angezeigt wird? –

+0

Es ist nicht so schlimm, wenn man es kaputt macht. Es lohnt sich, Dekorateure irgendwann zu verstehen, aber sie sind ein ziemlich fortgeschrittenes Thema. Nützlich, obwohl. Wichtig ist, dass Sie einen Dekorator auf einen Funktionsblock anwenden, mit dem Sie diese Funktion automatisch wiederholen können, wenn ein bestimmter Satz von Ausnahmen ausgelöst wird. Sehr nützlich, wenn Sie eine Reihe von Funktionen haben, die alle wiederholt werden müssen - Sie können einfach den '@ retry'-Dekorator auf jede Funktionsdefinition anwenden. –

+0

Danke, es läuft, einige Stunden/Tage und ich kann es überprüfen und ich hoffe, es funktioniert: D –