python 爬虫的重试机制(二)
0 背景
在之前我们提到了python requests自带的重试机制, 可以让网络请求在超时或者特定的响应码进行重试, 可以增加我们抓取请求成功的机会.
那在面对更复杂的情况时, 我们应该如何进行重试呢? 比如, 当我们判断response.text
存在no data
时就重试, 应该如何设置重试条件呢?
我们可以使用一个第三方的重试框架retrying
.
retrying
是一个 Python 库,用于简化在失败时重试函数调用的过程。这个库真的是非常滴有用,尤其是在处理网络请求、远程服务调用或任何可能因暂时性问题(如网络延迟、服务不可用等)而失败的操作时。
下面是 retrying
的一些主要特点和优点:
-
灵活的重试策略:
retrying
允许我们自定义重试策略,例如设置最大重试次数、重试等待时间等。 -
装饰器支持:它通过装饰器提供了一种简单的方式来应用重试逻辑。我们只需将装饰器添加到需要重试的函数上。
-
条件重试:
retrying
支持基于异常类型或返回值的条件重试。比如,我们可以指定仅当特定类型的异常被抛出时才重试。 -
等待策略:支持多种等待策略,如固定时间等待、指数退避等待等,这有助于更有效地处理重试。
-
停止策略:我们可以定义何时停止重试,如达到最大尝试次数或超过指定的时间限制。
-
调试和日志记录:
retrying
还支持调试和日志记录,这有助于我们开发和调试重试逻辑。 -
简单易用:最后但同样重要的是,
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学习资料,包含面试题、简历资料等具体看下方。
一、Python所有方向的学习路线
Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照下面的知识点去找对应的学习资源,保证自己学得较为全面。
二、Python必备开发工具
工具都帮大家整理好了,安装就可直接上手!
三、最新Python学习笔记
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、Python视频合集
观看全面零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
五、实战案例
纸上得来终觉浅,要学会跟着视频一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
六、面试宝典
简历模板![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e609d9de17e680ccba27f351612a0860.png#pic_center)
![](https://i-blog.csdnimg.cn/blog_migrate/cb395cecff5ad75a8ea79120f52bfaae.png)