python爬虫多次请求超时的几种重试方法(6种)

  • Post category:Python

Python爬虫在进行多次请求的过程中,有时会出现请求超时的情况,这时我们可以使用重试机制来尝试多次请求。本文将介绍六种常见的Python爬虫重试方法。

第一种方法:使用requests库的timeout和retry参数

requests库本身提供了timeout和retry两个参数,我们可以使用它们来实现请求超时后的重试。

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry

# 创建重试策略
retry_strategy = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[500, 502, 503, 504]
)

# 创建session
session = requests.Session()
session.mount("http://", HTTPAdapter(max_retries=retry_strategy))

# 发送请求
try:
    response = session.get('http://www.example.com', timeout=5)
    print(response.status_code)
except Exception as e:
    print(e)

该代码中,total表示重试次数,backoff_factor表示重试间隔时间的乘数因子,status_forcelist表示需要重试的HTTP状态码列表。我们使用Session对象来管理这个请求和它的重试。使用timeout设置请求超时时间,若请求超时,将会发生异常。

第二种方法:使用requests库和retrying库

retrying库可以在请求失败时实现自动重试,结合requests库可以方便地实现重试功能。

import requests
from retrying import retry

# 使用retrying装饰器
@retry
def get_response():
    response = requests.get('http://www.example.com')
    return response

# 调用函数
try:
    response = get_response()
    print(response.status_code)
except Exception as e:
    print(e)

使用retrying库的retry装饰器来实现请求失败时的重试。默认情况下,retrying会在发生异常时重试3次。可以通过添加参数来自定义重试次数和重试间隔时间。

第三种方法:使用urllib库和time库

使用urllib库和time库可以实现简单的重试机制。

import urllib.error
import urllib.request
import time

# 发送请求
def get_response():
    count = 0
    while count < 3:
        try:
            response = urllib.request.urlopen('http://www.example.com', timeout=5)
            return response.read()
        except urllib.error.URLError as e:
            if hasattr(e, 'code') and e.code >= 500 and e.code < 600:
                print(f'Server error: {e.code}, Retry in 5 seconds...')
                time.sleep(5)
                count += 1
            else:
                raise e
    raise Exception(f'Request Error after {count} times retry.')

# 调用函数
try:
    response = get_response()
    print(response)
except Exception as e:
    print(e)

我们在get_response函数中使用while循环,判断请求次数是否小于3。若请求成功,返回response,否则判断异常类型是否是URLError,和状态码是否在500-599之间。若是,则等待5秒后重试,次数加1;否则,重新抛出异常。当请求次数达到3时,抛出异常。

第四种方法:使用timeout-decorator库

timeout-decorator库可以方便地为函数添加超时机制和重试机制。

from timeout_decorator import timeout, TimeoutError
from retrying import retry

# 使用timeout-decorator和retrying库
@timeout(5)
@retry(stop_max_attempt_number=3)
def get_response():
    response = requests.get('http://www.example.com')
    return response

# 调用函数
try:
    response = get_response()
    print(response.status_code)
except TimeoutError as t_error:
    print(t_error)
except Exception as e:
    print(e)

timeout-decorator库的timeout装饰器可以为函数添加超时机制,retrying库的retry装饰器可以为函数添加重试机制。由于timeout-decorator库自带超时机制,我们可以省略掉requests库中的timeout参数。stop_max_attempt_number表示最大重试次数。

第五种方法:使用tenacity库

Tenacity库是一个用于重试、回退和错误处理的Python库,可以方便地实现重试机制。

from tenacity import retry, stop_after_attempt, wait_fixed

# 使用tenacity库的retry装饰器
@retry(stop=stop_after_attempt(3), wait=wait_fixed(5))
def get_response():
    response = requests.get('http://www.example.com')
    return response

# 调用函数
try:
    response = get_response()
    print(response.status_code)
except Exception as e:
    print(e)

使用tenacity库的retry装饰器来实现请求失败时的重试。使用stop_after_attempt函数设置最大重试次数,wait_fixed函数设置重试间隔时间。

第六种方法:使用backoff库

backoff库可以根据指数函数产生延迟时间,可以实现前几次请求间隔短,后面的请求间隔时间逐步增加的效果。

from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
import backoff

# 创建重试策略
retry_strategy = Retry(
    total=3,
    backoff_factor=1,
    status_forcelist=[500, 502, 503, 504]
)

# 使用backoff库的on_predicate装饰器
@backoff.on_predicate(backoff.expo, max_tries=3)
def get_response():
    session = requests.Session()
    session.mount("http://", HTTPAdapter(max_retries=retry_strategy))
    response = session.get('http://www.example.com')
    return response

# 调用函数
try:
    response = get_response()
    print(response.status_code)
except Exception as e:
    print(e)

在get_response函数中,我们使用on_predicate装饰器来设置函数执行失败时的重试策略。使用backoff.expo函数设置间隔时间的指数因子。max_tries表示最大重试次数。我们使用session对象来实现请求和重试,而不是使用requests库中的retry参数。