在嵌套递归方法

时间:2015-08-21 09:17:21

标签: python loops recursion nested-loops

我正在使用网络抓取工具。抓取工具是为具有多个类别的网页构建的。这些类别可以有子类别,子类别也是如此。

所以它看起来像这样:

enter image description here

所以我做了一个递归方法,它提供了深度的第一次搜索。

def deep_search(url):

    if is_leaf(url):
       return get_data(url)

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

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

如果发生错误并且下次从此状态继续,您将如何记住状态?

我不能记得最后一次' url'或类别,因为有循环,程序不知道什么' urls'和类别已存储在上部循环中。

2 个答案:

答案 0 :(得分:1)

如果搜索路径的顺序是稳定的(每次脚本以相同的顺序访问子类别),那么您可以在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的来源,但我想它实现了上述所有内容,等等。

答案 1 :(得分:0)

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

演示:

来自集合import 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语言软件包,用于创建,操作和研究复杂网络的结构,动态和功能。