【问题标题】:Errno 10054 while scraping HTML with Python: how to reconnect使用 Python 抓取 HTML 时出现 Errno 10054:如何重新连接
【发布时间】:2014-04-25 16:56:10
【问题描述】:

我是一名 Python 程序员新手,我试图使用 Python 从 fanfiction.net 中抓取大量页面,并将页面 HTML 源代码的特定行存入 .csv 文件。我的程序运行良好,但最终遇到了停止运行的障碍。我的 IDE 告诉我程序遇到了“Errno 10054:现有连接被远程主机强行关闭”。

我正在寻找一种方法来让我的代码在每次收到错误时重新连接并继续。我的代码每次运行都会抓取几十万页;这对网站来说可能太多了吗?该网站似乎无法防止抓取。我已经对这个问题进行了大量研究并尝试实现重试装饰器,但装饰器似乎不起作用。这是我的代码的相关部分:

def retry(ExceptionToCheck, tries=4, delay=3, backoff=2, logger=None):

    def deco_retry(f):

        @wraps(f)
        def f_retry(*args, **kwargs):
            mtries, mdelay = tries, delay
            while mtries > 1:
                try:
                    return f(*args, **kwargs)
                except ExceptionToCheck as e:
                    msg = "%s, Retrying in %d seconds..." % (str(e), mdelay)
                    if logger:
                        logger.warning(msg)
                    else:
                        print(msg)
                    time.sleep(mdelay)
                    mtries -= 1
                    mdelay *= backoff
            return f(*args, **kwargs)

        return f_retry  # true decorator

    return deco_retry


@retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
def retrieveURL(URL):
    response = urllib.request.urlopen(URL)
    return response


def main():
    # first check: 5000 to 100,000 
    MAX_ID = 600000
    ID = 400001
    URL = "http://www.fanfiction.net/s/" + str(ID) + "/index.html"
    fCSV = open('buffyData400k600k.csv', 'w')
    fCSV.write("Rating, Language, Genre 1, Genre 2, Character A, Character B, Character C,     Character D, Chapters, Words, Reviews, Favorites, Follows, Updated, Published, Story ID, Story Status, Author ID, Author Name" + '\n')    

    while ID <= MAX_ID:

        URL = "http://www.fanfiction.net/s/" + str(ID) + "/index.html"
        response = retrieveURL(URL)

每当我在我的 IDE 之外运行 .py 文件时,它最终会在大约一个小时后锁定并停止抓取新页面。我还在我的 IDE 中运行同一文件的不同版本,而且现在似乎已经运行了将近 12 个小时,如果不是更长的话——该文件是否有可能在我的 IDE 中运行,但在独立运行时不能运行?

我的装饰器设置错了吗?我还能做些什么来让 python 重新连接?我还看到有人声称 SQL 本地客户端过时可能会给像我这样的 Window 用户带来问题——这是真的吗?我试图更新它,但没有运气。

谢谢!

【问题讨论】:

  • 我认为提供的代码末尾的while 循环比您显示的要多,对吧?否则你有一个无限循环
  • 是的!我不想发布整个内容,因为在 while 循环中,代码继续进行大量字符串格式化。我已经确认代码没有陷入任何无限循环,因为我有一个打印命令,指示代码何时检索到新 URL 并提取其 HTML。
  • 附带说明,您可能需要查看Python Requests library。我发现它比 urllib 更容易使用。

标签: python html runtime-error screen-scraping


【解决方案1】:

您正在捕获 URLErrors,而 Errno: 10054 没有,因此您的 @retry 装饰器不会重试。试试这个。

@retry(Exception, tries=4)
def retrieveURL(URL):
    response = urllib.request.urlopen(URL)
    return response

这应该对任何异常重试 4 次。您的 @retry 装饰器定义正确。

【讨论】:

  • @Rob Watts 的回答也可以,但我个人倾向于更全面的重新连接。您的代码会运行,因此通常您并不真正关心错误是什么,您只想尝试重新连接而不考虑错误。
  • 有道理!我现在觉得很傻。感谢您的帮助!
  • 别傻了——当我刚开始的时候,重试装饰器让我很困惑。有时第二只眼睛会有所帮助
【解决方案2】:

您的重新连接代码看起来不错,除了一部分 - 您试图捕获的异常。根据this StackOverflow questionErrno 10054socket.error。您需要做的就是import socket 并在您的重试处理程序中添加一个except socket.error 语句。

【讨论】:

  • 谢谢!感谢您的帮助。
猜你喜欢
  • 2016-05-30
  • 1970-01-01
  • 2012-02-07
  • 1970-01-01
  • 2011-06-06
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
相关资源
最近更新 更多