2017-09-20 1 views
0

수천 링크에서 작동하는 웹 스크래핑 스크립트가 있습니다. 하지만 가끔은 내가 연결 오류, 타임 아웃 오류, 잘못된 게이트웨이 오류가 내 스크립트가 그만입니다 .. 다음 debian에서 파이썬으로 웹 스크래핑 할 때 연결 오류, 시간 초과가 발생했습니다.

코드 내 일부

(내가 루프 실행 사람의 URL에 내가 가지고 링크) :

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" }) 

나는 이것을 피하기 위해 try-catch methode를 사용해야한다고 생각하며,이 웹 사이트를 다시 읽으려고 시도하고있다.

내 질문은 어디에서 무엇이 내가 내 코드에 빌드해야 이러한 오류를 포착하고 다시 시도/다음 링크로 이동합니까?

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? 

고맙습니다!

+0

때때로 서버의 시간 제한이 30 초로 제한되어 있습니다. 이는 시간 제한 내에 스크립트가 완료되지 않으면 스크립트가 종료된다는 것을 의미합니다. 이것이 이유 인 경우 셀러리를 사용하여 백그라운드 작업에서이 근근이 살아가는 것을 사용할 수 있습니다. –

+0

나는 셀러리를 전혀 사용하지 않았고 리눅스 + 파이썬에서 완전히 초보자이기 때문에 try-except 메소드로 해결할 수 없다면 작업 스케줄링 (crom)으로 스크립트를 다시 열어 보자. –

답변

1

이전에 이런 종류의 오류를 다루었을 때, 주어진 예외가 발생하면 특정 횟수만큼 함수 호출을 다시 시도하는 데코레이터를 작성했습니다.

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 
당신은 함수 (최대가 시도 후) 실패한 호출을 처리 할 수 ​​

:

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 

이 기능을 장식하는 클래스의 인스턴스를 확인 호출 : retreat=2

#Class instance to use as a retry decorator 
retry = Retry(times=5, pause=1, retreat=2, cleanup=failed_call, 
       exceptions=(RequestException, timeout)) 

첫 번째 재 시도는 1 초 후, 두 번째 재 시도는 2 초 후, 세 번째 재시도는 4 초 후 등

(210)

그리고 당신의 재시도 장식으로 장식 된 웹 사이트, 긁어 함수를 정의 : 쉽게 재 시도를 트리거하는 예외를 설정할 수 있습니다

@retry 
def scrape_a_site(url, params): 
    r = requests.get(url, params=params) 
    return r 

참고. 여기에 RequestExceptiontimeout을 사용했습니다. 귀하의 상황에 적응하십시오.

#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" }) 

주 당신의 작은 블록에 @retry을 적용 :

코드와 관련하여

, 당신은 (위의 코드의 첫 번째 블록으로 장식을 규정 한) 이런 식으로 뭔가에 적응 할 수 코드 수 (그냥 웹 조회 논리).

+0

와우, 그 매우 복잡한 게시물, 감사합니다! 그것을 코드에 어떻게 추가 할 수 있을까요? –

+0

당신이 그것을 무너 뜨릴 때 나쁘지 않습니다. 어느 시점에서 데코레이터를 이해하는 것은 가치가 있지만, 상당히 고급 주제입니다. 유용하지만. 중요한 것은 특정 예외 집합이 발생하면 함수를 자동으로 다시 시도 할 수 있도록 데코레이터를 함수 블록에 적용한다는 것입니다. 모든 함수를 재 시도해야하는 경우 매우 유용합니다. 각 함수 정의에'@ retry' 데코레이터를 적용하면됩니다. –

+0

고맙습니다. 작동되고 있습니다. 몇 시간/일이며 점검 할 수 있습니다. 작동하고 싶습니다. D –

관련 문제