在做数据抓取的时候,经常遇到网络问题导致的程序保存问题。之前我只是记录错误内容,并对错误内容进行后期处理。原流程:defcrawl_page(url):passdeflog_error(url):passurl=""try:crawl_page(url)except:log_error(url)改进流程:attempts=0success=Falsewhileattempts<3andnotsuccess:try:crawl_page(url)success=Trueexcept:attempts=1ifattempts==3:break最近发现一个新的解决方案:retryingretrying是一个Python重试包,可以用来自动重试一些可能失败的程序段。retrying提供了一个装饰器函数retry,被装饰的函数在运行失败的情况下会重新执行。默认情况下,只要它一直报告错误,它就会继续重试。importrandomfromretryingimportretry@retrydefdo_something_unreliable():ifrandom.randint(0,10)>1:raiseIOError("Brokensauce,everythingishosed!!!111one")else:return"Awesomesauce!"printdo_something_unreliable()如果我们运行haveatry函数,那么直到Return5,才会执行,否则重新执行。retry也可以接受一些参数。可以从源码中Retrying类的初始化函数中看到可选参数:stopmaxattempt_number:用于设置***尝试的次数,超过这个次数就停止重试stopmaxdelay:比如设置为10000,那么只要被装饰函数开始执行到函数成功结束或失败报错的时间超过10秒,该函数就不会被执行。wait_fixed:设置两次重试之间的停留时间waitrandommin和waitrandommax:随机生成两次重试之间的停留时间waitexponentialmultiplier和waitexponentialmax:以索引的形式生成两次重试之间的停留时间,生成的值为2^previousattemptnumber*waitexponentialmultiplier,previousattemptnumber是之前的重试次数。如果生成的值超过waitexponentialmax的大小,那么两次重试之间的停留值为waitexponentialmax。这种设计迎合了指数退避算法,可以缓解阻塞情况。我们可以指定有异常时重试哪些异常。这需要retryoneexception传入一个函数对象:defretry_if_io_error(exception):returnisinstance(exception,IOError)@retry(retry_on_exception=retry_if_io_error)defread_a_file():withopen("file","r")asf:returnf.read()期间readafile函数的执行,如果报异常,会将该异常传入形参exception的retryifio_error函数中。如果异常是IOError,那么将执行重试。如果不是,则停止运行并抛出异常。我们还可以指定在获取结果时要重试的结果。这是使用retryonresult传入一个函数对象:defretry_if_result_none(result):returnresultisNone@retry(retry_on_result=retry_if_result_none)defget_result():returnNonegetresult执行成功后,会将函数的返回值传递给retryifresultnone函数形式参数形式为result。如果返回值为None,则重试,否则结束并返回函数值。其他相关资料:https://pypi.python.org/pypi/retry/https://julien.danjou.info/blog/2015/python-retryinghttps://github.com/rholder/retrying
