【问题标题】:Continue (save state) in nested recursive method以嵌套递归方法继续(保存状态)
【发布时间】:2015-11-15 04:30:07
【问题描述】:

我正在开发一个网络爬虫。爬虫是为具有许多类别的网页而构建的。这些类别可以有子类别,子类别等也是如此。

所以它看起来像这样:

所以我做了一个递归方法,提供深度优先搜索。

def deep_search(url):

    if is_leaf(url):
       return get_data(url)

    for url in get_subcategories(url):
        deep_search(url)

此方法工作正常,但需要很长时间才能完成,因此有时会出现连接中断或引发其他错误的情况。

如果发生错误以及下次从该状态继续,您会如何记住状态?

我不能只记住最后一个“url”或类别,因为存在循环并且程序不知道哪些“url”和类别已存储在上层循环中。

【问题讨论】:

  • 你确定这还能用吗?如果 url 是叶 url,则在返回数据时,您似乎正在丢弃数据,在行中 - for url in get_subcategories(url): deep_search(url)
  • 只是想确保您知道Scrapy
  • 看看 Scrapy,如果你还没有。
  • @AnandSKumar 这只是伪代码,实际上要困难得多。但是,是的,它有效。问题是如何记住状态。但感谢您的评论。
  • 一般情况下,您希望创建一个 url 池来抓取并创建一组工作者(线程),这些工作者(线程)从池中获取 url 进行处理(提取数据并将新的 url 添加到池中,如果有的话)一页)

标签: python loops recursion nested-loops


【解决方案1】:

作为一个简单的提示,您可以使用try-except 语句来处理您的错误并保存相关的url,作为此类任务的一个不错的选择,您可以使用具有1 个容量的collections.deque,并在下一次迭代中检查它.

演示:

从集合导入双端队列

def deep_search(url,deq=deque(maxlen=1)):

    if is_leaf(url):
       return get_data(url)
  try:
    for url in get_subcategories(url):
      if deq[0]==url:
        deep_search(url,deq)

  except : #you can put the error title after except 
    deq.append(url)

但作为处理网络的更 Pythonic 方式,您可以使用 networkx

NetworkX 是一个 Python 语言软件包,用于创建、操作和研究复杂网络的结构、动力学和功能。

【讨论】:

    【解决方案2】:

    如果搜索路径的顺序是稳定的(每次您的脚本以相同的顺序访问子类别),那么您可以在 DFS 中维护一个分支编号列表,并使其持久化——将其保存在文件或数据库中:

    current_path = [] # save the path currently visited
    
    def deep_search(url, last_saved_path=None):
       if is_leaf(url):
           if last_saved_path:
               # Continue where you left off
               if path_reached(last_saved_path):
                   data = get_data(url)
           else:    # first run
               data = get_data(url)        
           # save the whole path persistently
           save_to_file(current_path)
           # add data to result
       else:
           for index, url in enumerate(get_subcategories(url)):
               current_path.append(index)
               deep_search(url, last_saved_path)
               del current_path[-1]
    
    def path_reached(old_path):
        print old_path, current_path
        # if the path has been visited in last run
        for i,index in enumerate(current_path):
            if index < old_path[i]:
                return False
            elif index > old_path[i]:
                return True
        return True
    

    第二次运行爬虫时,可以加载保存的路径,从上次中断的地方开始:

    # first run 
    deep_search(url)
    # subsequent runs
    last_path = load_last_saved_path_from_file()
    deep_search(url, last_path)
    

    也就是说,我认为网络爬虫有两种任务:遍历图和下载数据。并且最好将它们分开:使用上面的DFS算法(加上跳过已访问路径的逻辑)遍历链接,并将下载url保存在队列中;然后启动一堆工人从队列中获取 url 并下载。这样,如果被打断,你只需要记录队列中的当前位置。

    我向你推荐scrapy,我没有读过scrapy源码,但我猜它实现了以上所有,等等。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-09-07
      • 1970-01-01
      • 1970-01-01
      • 2019-06-25
      • 1970-01-01
      • 2018-02-04
      • 2017-07-08
      • 1970-01-01
      相关资源
      最近更新 更多