Python重试模块retrying
Python重试模块retrying
工作中经常碰到的问题就是,某个方法出现了异常,重试几次。循环重复一个方法是很常见的。比如爬虫中的获取代理,对获取失败的情况进行重试。
刚开始搜的几个博客讲的有点问题,建议看官方文档,还有自己动手实验。
参考:
https://segmentfault.com/a/1190000004085023
https://pypi.org/project/retrying/
最初的版本
import requests
class ProxyUtil:
def __init__(self):
self._get_proxy_count = 0
def get_proxies(self):
try:
r = requests.get('代理服务器地址')
# print('正在获取')
# raise Exception("异常")
# print('获取到最新代理 = %s' % r.text)
params = dict()
if r and r.status_code == 200:
proxy = str(r.content, encoding='utf-8')
params['http'] = 'http://' + proxy
params['https'] = 'https://' + proxy
else:
raise Exception("获取代理失败,状态码%s"%(r.status_code))
return params
except Exception:
if self._get_proxy_count < 5:
print('第%d次获取代理失败,准备重试' % self._get_proxy_count)
self._get_proxy_count += 1
self.get_proxies()
else:
print('第%d次获取代理失败,退出' % self._get_proxy_count)
self._get_proxy_count = 0
return dict()
if __name__ == '__main__':
proxy = ProxyUtil()
proxy.get_proxies()
以上代码通过
try...except...捕获异常,并通过一个计数器判断获取代理的次数,获取失败递归调用自己,直到达到最大次数为止。
为了模拟失败,可以解开抛出异常的注释
下面来试试retrying模块
安装
pip install retrying
retrying提供一个装饰器函数retry,被装饰的函数会在运行失败的情况下重新执行,默认一直报错就一直重试。
import requests
from retrying import retry
class ProxyUtil:
def __init__(self):
self._get_proxy_count = 0
@retry
def get_proxies(self):
r = requests.get('代理地址')
print('正在获取')
raise Exception("异常")
print('获取到最新代理 = %s' % r.text)
params = dict()
if r and r.status_code == 200:
proxy = str(r.content, encoding='utf-8')
params['http'] = 'http://' + proxy
params['https'] = 'https://' + proxy
if __name__ == '__main__':
proxy = ProxyUtil()
proxy.get_proxies()
结果:
正在获取
正在获取
正在获取
...
正在获取(一直重复下去)
没有添加任何参数,默认情况下会一直重试,没有等待时间
# 设置最大重试次数
@retry(stop_max_attempt_number=5)
def get_proxies(self):
r = requests.get('代理地址')
print('正在获取')
raise Exception("异常")
print('获取到最新代理 = %s' % r.text)
params = dict()
if r and r.status_code == 200:
proxy = str(r.content, encoding='utf-8')
params['http'] = 'http://' + proxy
params['https'] = 'https://' + proxy
# 设置方法的最大延迟时间,默认为100毫秒(是执行这个方法重试的总时间)
@retry(stop_max_attempt_number=5,stop_max_delay=50)
# 通过设置为50,我们会发现,任务并没有执行5次才结束!
# 添加每次方法执行之间的等待时间
@retry(stop_max_attempt_number=5,wait_fixed=2000)
# 随机的等待时间
@retry(stop_max_attempt_number=5,wait_random_min=100,wait_random_max=2000)
# 每调用一次增加固定时长
@retry(stop_max_attempt_number=5,wait_incrementing_increment=1000)
# 根据异常重试,先看个简单的例子
def retry_if_io_error(exception):
return isinstance(exception, IOError)
@retry(retry_on_exception=retry_if_io_error)
def read_a_file():
with open("file", "r") as f:
return f.read()
read_a_file函数如果抛出了异常,会去retry_on_exception指向的函数去判断返回的是True还是False,如果是True则运行指定的重试次数后,抛出异常,False的话直接抛出异常。
当时自己测试的时候网上一大堆抄来抄去的,意思是retry_on_exception指定一个函数,函数返回指定异常,会重试,不是异常会退出。真坑人啊!
来看看获取代理的应用(仅仅是为了测试retrying模块)
# 定义一个函数用于判断返回的是否是IOError
def wraper(args):
return isinstance(args,IOError)
class ProxyUtil:
def get_proxies(self):
r = requests.get('http://47.98.163.40:17000/get?country=local')
print('正在获取')
raise IOError
# raise IndexError
print('获取到最新代理 = %s' % r.text)
params = dict()
if r and r.status_code == 200:
proxy = str(r.content, encoding='utf-8')
params['http'] = 'http://' + proxy
params['https'] = 'https://' + proxy
# @retry_handler(retry_time=2, retry_interval=5, retry_on_exception=[IOError,IndexError])
@retry(stop_max_attempt_number=5,retry_on_exception=wraper)
def retry_test(self):
self.get_proxies()
print('io')
这种方法只能判断单一的异常,而且扩展性不够高
# 通过返回值判断是否重试
def retry_if_result_none(result):
"""Return True if we should retry (in this case when result is None), False otherwise"""
# return result is None
if result =="111":
return True
@retry(stop_max_attempt_number=5,retry_on_result=retry_if_result_none)
def might_return_none():
print("Retry forever ignoring Exceptions with no wait if return value is None")
return "111"
might_return_none()
might_return_none函数的返回值传递给retry_if_result_none的result,通过判断result,返回Treu或者None表示需要重试,重试结束后抛出RetryError,返回False表示不重试。
扩展默认的retry装饰器:
def retry_handler(retry_time: int, retry_interval: float, retry_on_exception: [BaseException], *args, **kwargs):
def is_exception(exception: [BaseException]):
for exp in retry_on_exception:
if isinstance(exception,exp):
return True
return False
# return isinstance(exception, retry_on_exception)
def _retry(*args, **kwargs):
return Retrying(wait_fixed=retry_interval * 1000).fixed_sleep(*args, **kwargs)
return retry(
wait_func=_retry,
stop_max_attempt_number=retry_time,
retry_on_exception=is_exception
)
class ProxyUtil:
def get_proxies(self):
r = requests.get('代理地址')
print('正在获取')
raise IOError
# raise IndexError
print('获取到最新代理 = %s' % r.text)
params = dict()
if r and r.status_code == 200:
proxy = str(r.content, encoding='utf-8')
params['http'] = 'http://' + proxy
params['https'] = 'https://' + proxy
@retry_handler(retry_time=2, retry_interval=5, retry_on_exception=[IOError,IndexError])
# @retry(stop_max_attempt_number=5,retry_on_exception=wraper)
def retry_test(self):
self.get_proxies()
print('io')
if __name__ == '__main__':
proxy = ProxyUtil()
proxy.retry_test()
Python重试模块retrying的更多相关文章
- python重试库retryiny源码剖析
上篇博文介绍了常见需要进行请求重试的场景,本篇博文试着剖析有名的python第三方库retrying源码. 在剖析其源码之前,有必要讲一下retrying的用法,方便理解. 安装: pip insta ...
- Python标准模块--threading
1 模块简介 threading模块在Python1.5.2中首次引入,是低级thread模块的一个增强版.threading模块让线程使用起来更加容易,允许程序同一时间运行多个操作. 不过请注意,P ...
- Python的模块引用和查找路径
模块间相互独立相互引用是任何一种编程语言的基础能力.对于“模块”这个词在各种编程语言中或许是不同的,但我们可以简单认为一个程序文件是一个模块,文件里包含了类或者方法的定义.对于编译型的语言,比如C#中 ...
- Python Logging模块的简单使用
前言 日志是非常重要的,最近有接触到这个,所以系统的看一下Python这个模块的用法.本文即为Logging模块的用法简介,主要参考文章为Python官方文档,链接见参考列表. 另外,Python的H ...
- Python标准模块--logging
1 logging模块简介 logging模块是Python内置的标准模块,主要用于输出运行日志,可以设置输出日志的等级.日志保存路径.日志文件回滚等:相比print,具备如下优点: 可以通过设置不同 ...
- python基础-模块
一.模块介绍 ...
- python 安装模块
python安装模块的方法很多,在此仅介绍一种,不需要安装其他附带的pip等,python安装完之后,配置环境变量,我由于中英文分号原因,环境变量始终没能配置成功汗. 1:下载模块的压缩文件解压到任意 ...
- python Queue模块
先看一个很简单的例子 #coding:utf8 import Queue #queue是队列的意思 q=Queue.Queue(maxsize=10) #创建一个queue对象 for i in ra ...
- python logging模块可能会令人困惑的地方
python logging模块主要是python提供的通用日志系统,使用的方法其实挺简单的,这块就不多介绍.下面主要会讲到在使用python logging模块的时候,涉及到多个python文件的调 ...
随机推荐
- ubuntu 16.04 android studio 开发环境搭建
安装步骤: 1. 安装 Java developer kit 2.安装 Android developer kit 3.安装 Android studio 4.真机调试 第一次用Linux,命令基本不 ...
- delphi程序向另一个可执行程序发消息(使用GetForegroundWindow; 找出当前操作系统中活动的第一个窗口)
function FindWindowThroughWindowText(WindowText: string): THandle;var hCurrentWindow: THandle; cnt ...
- Natively Compiled Code: A Comeback?
RAD Studio and Natively Compiled Code In today's development landscape, natively compiled code is ma ...
- “多团队大规模”开发模式 - 基于SAP HANA平台的多团队产品研发
应用SAP HANA “官方”开发模式的伙伴们在转到“多团队大规模”开发模式时会遇到各式各样的心理不适应的状况,各种纠结.比如GIT Repository和HANA Repository冲突什么的. ...
- 原创powershell脚本:通过远程桌面3389黑名单,阻止黑客ip
远程桌面 3389 ban ip 防火墙 rdp 通过远程桌面3389黑名单,阻止黑客ip.这是一个常见的需求.但我搜遍了谷歌也找不到成品脚本.想做搬运工却做不成,只能自己费尽写.下载备用吧,估计 ...
- Hadoop集群(第2期)虚拟机网卡的介绍和配置
很多人安装虚拟机的时候,经常遇到不能上网的问题,而vmware有三种网络模式,对初学者来说也比较眼花聊乱,今天我就来基于虚拟机3种网络模式,帮大家普及下虚拟机上网的背景知识 虚拟机网络模式 无论是vm ...
- java关键字-abstract
抽象:不具体,看不明白. 抽象类表象体现. 在不断抽取过程中,将共性内容中的方法声明抽取,但是方法不一样,没有抽取,这时抽取到的方法,并不具体,需要被指定关键字abstract所标示,声明为抽象方法. ...
- ES 20 - 查询Elasticsearch中的数据 (基于DSL查询, 包括查询校验match + bool + term)
目录 1 什么是DSL 2 DSL校验 - 定位不合法的查询语句 3 match query的使用 3.1 简单功能示例 3.1.1 查询所有文档 3.1.2 查询满足一定条件的文档 3.1.3 分页 ...
- 『 效率工具 』Spring Boot版的轻量级代码生成器,减少70%以上的开发任务
一. 前言 之前很着迷于代码自动生成,减少写重复代码的工作量.网络上也搜索了很久,有基于插件的,有GUI的.但其配置和学习成本都比较高,都不是很如我意. 本想自己用SpringBoot写一个,在收集相 ...
- Exceptionless(二) - 使用进阶
Exceptionless(二) - 使用进阶 作者:markjiang7m2 原文地址:https://www.cnblogs.com/markjiang7m2/p/11100563.html 官网 ...