【问题标题】:Can You Retry/Loop inside a Try/Except?您可以在 Try/Except 中重试/循环吗?
【发布时间】:2020-08-12 02:35:50
【问题描述】:

我试图了解是否可以在 Try/Except 调用中设置循环,或者我是否需要重组以使用函数。长话短说,在花了几个小时学习 Python 和 BeautifulSoup 之后,我设法将一些代码拼凑在一起,以抓取 URL 列表,将数据提取到 CSV(现在将其更新到 MySQL 数据库)。代码现在按计划运行,除了我偶尔遇到 10054,可能是因为我的 VPN 打嗝,或者可能是源主机服务器偶尔弹跳我(我的循环中有 30 秒的延迟,但有时它仍然会踢我)。

我了解 Try/Except 结构的一般概念,但我不太确定我将如何(或者如果我可以)在其中循环以重试。我获取 URL、清理它并解析我需要的表的基本代码如下所示:

for url in contents:
    print('Processing record', (num+1), 'of', len(contents))
    if url:
        print('Retrieving data from ', url[0])
        html = requests.get(url[0]).text
        soup = BeautifulSoup(html, 'html.parser')
        for span in soup('span'):
            span.decompose()
       trs = soup.select('div#collapseOne tr')
        if trs:
            print('Processing')
            for t in trs:
                for header, value in zip(t.select('td')[0], t.select('td:nth-child(2)')):
                    if num == 0:
                        headers.append(' '.join(header.split()))    
                    values.append(re.sub(' +', ' ', value.get_text(' ', strip=True)))  

之后只是将数据处理为 CSV 并运行更新 sql 语句。

我想要做的是如果 HTML 请求调用失败是等待 30 秒,再次尝试请求,然后处理,或者如果重试失败 X 次,继续并退出脚本(假设那时点我有一个完整的连接失败)。

是否可以在线执行类似的操作,或者我需要将请求语句变成一个函数并设置一个循环来调用它?不得不承认我还不熟悉 Python 如何处理函数返回。

【问题讨论】:

    标签: python-3.x web-scraping beautifulsoup


    【解决方案1】:

    您可以为重试添加一个内部循环,并将您的 try/except 块放入其中。这是它的外观草图。您可以将所有这些放入一个函数中,并将该函数调用放在它自己的 try/except 块中,以捕获导致循环退出的其他错误。

    查看requests exception hierarchy,Timeout 涵盖了多个可恢复的异常,是您可能想要捕获的一切的良好开端。 SSLError 之类的其他事情不会因为您重试而变得更好,因此请跳过它们。你可以浏览一下列表,看看什么对你来说是合理的。

    import itertools
    
    # requests exceptions at 
    # https://requests.readthedocs.io/en/master/_modules/requests/exceptions/
        
    for url in contents:
        print('Processing record', (num+1), 'of', len(contents))
        if url:
            print('Retrieving data from ', url[0])
            retry_count = itertools.count()
            # loop for retries
            while True:
                try:
                    # get with timeout and convert http errors to exceptions
                    resp = requests.get(url[0], timeout=10)
                    resp.raise_for_status()
                # the things you want to recover from
                except requests.Timeout as e:
                    if next(retry_count) <= 5:
                        print("timeout, wait and retry:", e)
                        time.sleep(30)
                        continue
                    else:
                        print("timeout, exiting")
                        raise # reraise exception to exit
                except Exception as e:
                    print("unrecoverable error", e)
                    raise
                break
    
            html = resp.text
            etc…
    

    【讨论】:

    • 谢谢!快速提问。我看看你是否有例外,专门寻找超时,但如果我想睡觉/重试任何错误(我看到的主要错误是远程主机关闭连接)它仍然可以工作,只需将其更改为通用“除了: "声明?
    • 您可以更改为通用的 except,但是即使是像损坏的 url 这样的不可恢复的东西,您也会重试。我可能应该在文中提到它,但提供的链接显示 requests 特定错误。多个异常继承自Timeout,因此捕获了大部分可恢复的内容。
    • 您需要捕获的全部异常方式有点像发现之旅。你可以有一个泛型,除了 print("exception", e) 然后再加注以找出还有什么有用的。
    【解决方案2】:

    我自己做了一个小例子来绘制这个,是的,你可以在 try/except 块中放置循环。

    from sys import exit
    
    
    def example_func():
        try:
            while True:
                num = input("> ")
                try:
                    int(num)
                    if num == "10":
                        print("Let's go!")
                    else:
                        print("Not 10")
                except ValueError:
                    exit(0)
        except:
            exit(0)
    
    
    example_func()
    

    这是一个相当简单的程序,它接受输入,如果它是 10,那么它会说“我们走吧!”,否则它会告诉你它不是 10(如果它不是一个有效值,它就会把你踢出去)。

    请注意,在while 循环中,我放置了一个try/except 块,并考虑了必要的缩进。您可以将此程序作为模型并根据您的喜好使用它。

    【讨论】:

    • + 没有尝试,它工作得很好。这只是一个小例子。
    • 所以把它放在我的代码上下文中:``` while true: try: [http request call] except: wait(30) else: break() ``` 如果我是想通了,那么如果连接成功,就会结束While True循环,继续处理。但是在Except中,30秒睡眠后会发生什么? while 循环会再次循环并尝试连接吗?
    • 由于 try/except 块在 while 循环内,它会永远循环,直到出现错误或类似的东西,所以是的,它会再次尝试连接。 (else 用于if 语句,让您知道)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 1970-01-01
    • 2016-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多