python 爬虫的重试机制(二)

python 爬虫的重试机制(二)

0 背景

python 爬虫的重试机制(二)

在之前我们提到了python requests自带的重试机制, 可以让网络请求在超时或者特定的响应码进行重试, 可以增加我们抓取请求成功的机会.

那在面对更复杂的情况时, 我们应该如何进行重试呢? 比如, 当我们判断response.text 存在no data时就重试, 应该如何设置重试条件呢?

我们可以使用一个第三方的重试框架retrying.

retrying 是一个 Python 库,用于简化在失败时重试函数调用的过程。这个库真的是非常滴有用,尤其是在处理网络请求、远程服务调用或任何可能因暂时性问题(如网络延迟、服务不可用等)而失败的操作时。

下面是 retrying 的一些主要特点和优点:

  1. 灵活的重试策略retrying 允许我们自定义重试策略,例如设置最大重试次数、重试等待时间等。

  2. 装饰器支持:它通过装饰器提供了一种简单的方式来应用重试逻辑。我们只需将装饰器添加到需要重试的函数上。

  3. 条件重试retrying 支持基于异常类型或返回值的条件重试。比如,我们可以指定仅当特定类型的异常被抛出时才重试。

  4. 等待策略:支持多种等待策略,如固定时间等待、指数退避等待等,这有助于更有效地处理重试。

  5. 停止策略:我们可以定义何时停止重试,如达到最大尝试次数或超过指定的时间限制。

  6. 调试和日志记录retrying 还支持调试和日志记录,这有助于我们开发和调试重试逻辑。

  7. 简单易用:最后但同样重要的是,retrying 非常简单易用,它可以轻松集成到我们现有的 Python 项目中。

1 使用

retrying是一个第三方模块, 需要额外安装:

pip install retrying

简要说明以下这个包的一些参数, 该包是通过装饰器对函数进行重试的. 一些有条件的参数, 写在装饰器函数retry()

retry                                            # 不加参数表示无限重试
retry(wait_fixed = 100)                          # 设置重试间隔时长,单位:ms,1000ms = 1s
retry(wait_random_min=100,wait_random_max=200)   # 随机重试间隔,将在100ms - 200ms内
retry(stop_max_attempt_number = 4)               # 最大重试次数,超过后正常抛出异常
retry(stop_max_delay=1)                          # 最大延迟时长,1ms内未满足条件则抛出异常
retry(retry_on_exception = user_define_function)           # 当发生指定异常时会执行函数
retry(retry_on_result=user_define_function)                # 每次都会执行函数,当返回返回True就重试,否则异常退出

我们先模拟一个简单的爬虫, 当然, 重试机制不一定只在爬虫上, 可以应用到很多场景, 爬虫请求往往会收到网络 | 反爬等一些影响, 导致一次请求不会成功, 因此, 重试机制可以有效避免爬虫请求出现异常的情况.

我们先模拟一个简单的爬虫, 并且会出现了错误的爬虫. 待会会用到重试模块, 有条件的重试可以帮助爬虫提升抓取能力.

from retrying import retry
import time
import requests


def spider():
    print('spider engine start work.')
    time.sleep(2)
    raise requests.exceptions.ReadTimeout('超时请求错误')


if __name__ == '__main__':
    spider()

1 重试次数

@retry()
def spider():
    print('spider engine start work.')
    time.sleep(2)
    raise requests.exceptions.ReadTimeout('超时请求错误')

出现异常就会无限重试, 以上的结果当然是无限输出spider engine start work., 在爬虫当中, 这是不可取的.

stop_max_attempt_number

@retry(stop_max_attempt_number=5)
def spider():
    print('spider engine start work.')
    time.sleep(2)
    raise requests.exceptions.ReadTimeout('超时请求错误')

使用stop_max_attempt_number参数设置最大重试次数, 在爬虫引擎中, 有时候因为因为网络或代理IP失效等突然的原因导致请求失败, 设置最大重试次数, 可以减少这种临时的问题.

2 重试时间

stop_max_delay

@retry(stop_max_delay=5000)
def spider():
    print('spider engine start work.')
    time.sleep(10)
    raise requests.exceptions.ReadTimeout('超时请求错误')

这个我其实有点难以理解的, 后面我多去测试了几次: 使用stop_max_delay参数设置最大的重试时间, 这个是一个总的整个的所有的重试运行的时间, 如果出现了异常, 此时就需要重试, 正常会无限运行, 但是通过stop_max_delay当该函数运行超过5000毫秒的时候(上面的例子), 就不再重试了, 这样就可以在异常发生后及时处理, 也可以减少资源占用.

注意, 这个参数值的单位是毫秒.

wait_random_min & wait_random_max

@retry(wait_random_min=1000, wait_random_max=5000)
def spider():
    print(f'{time.time()} spider engine start work.')
    time.sleep(3)
    print(f'{time.time()} spider engine now working.')
    raise requests.exceptions.ReadTimeout('超时请求错误')

使用wait_random_min & wait_random_max参数可以出现异常后, 指定隔随机毫秒再运行, 这不就是为爬虫定制的参数吗!

wait_fixed

@retry(wait_fixed=5000)
def spider():
    print('spider engine start work.')
    time.sleep(2)
    print('spider engine now working.')
    raise requests.exceptions.ReadTimeout('超时请求错误')

使用wait_fixed参数时, 可以让函数出现异常时, 在特定时间后, 再继续运行, 在爬虫当时, 可以避免一些因抓取过快导致的爬虫问题, 这个参数比随机时间规律些.

3 异常的额外处理

stop_func

def get_now():
    return datetime.now().strftime("%H:%M:%S")


def send_msg_to_wechat():
    ...


def error_func(attempts, delay):
    print(f'{attempts=}{delay=} ')
    if attempts > 3:
        send_msg_to_wechat()
    return attempts > 3


@retry(stop_func=error_func)
def spider():
    print(f'{get_now()} spider engine start work.')
    time.sleep(3)
    print(f'{get_now()} spider engine now working.')
    raise requests.exceptions.ReadTimeout('超时请求错误')

这里, 使用stop_func参数, 可以在当函数出现异常时, 交给其他函数处理. 比如, 当我的爬虫出现错误时而且错误次数出现参数时, 我就将异常情况发送到微信, 并且停止运行, stop_func接收了一个异常处理函数, 在上面的例子我指定了error_func, error_func接受两个参数, attempts表示重试运行的次数, delay表示重试期间运行的时间(毫秒).

2 关于

使用 retrying,可以让我们更容易地编写更健壮和牛X稳定的代码,特别是在处理不稳定或不确定环境时。所以我们可以试试这个框包。

欢迎关注我的微信公众号


原文始发于微信公众号(其之):python 爬虫的重试机制(二)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/204860.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!