【问题标题】:Python recursive crawling for urlsPython递归爬取url
【发布时间】:2011-10-09 23:07:03
【问题描述】:

我有这种方法,当提供链接列表时,将获取子链接等等:

def crawlSite(self, linksList):
    finalList = []
    for link in list(linksList):
        if link not in finalList:
            print link            
            finalList.append(link)
            childLinks = self.getAllUniqueLinks(link)
            length = len(childLinks)
            print 'Total links for this page: ' + str(length)

        self.crawlSite(childLinks)
    return finalList

它最终会重复使用相同的链接集,我似乎无法弄清楚。当我在 if 语句中移动 self.crawlSite(childLinks) 时。我一遍又一遍地重复列表中的第一项。

self.getAllUniqueLinks(link) 方法的背景知识从给定页面获取链接列表。它过滤给定域内的所有可点击链接。基本上我想做的是从网站上获取所有可点击的链接。如果这不是所需的方法。你能推荐一种更好的方法来做同样的事情吗?另请考虑我对 python 相当陌生,可能不了解更复杂的方法。所以请解释一下你的思维过程。如果你不介意:)

【问题讨论】:

    标签: python function recursion hyperlink web-crawler


    【解决方案1】:

    你需要

    finalList.extend(self.crawlSite(childLinks))
    

    不只是

    self.crawlSite(childLinks)
    

    您需要将内部crawlSite()s 返回的列表与外部crawlSite() 中已经存在的列表合并。尽管它们都被称为finalList,但您在每个范围内都有不同的列表。

    另一种(更好的)解决方案是让 finalList 成为一个实例变量(或某种类型的非局部变量),而不仅仅是一个局部变量,以便它被crawlSite()s 的所有范围共享:

    def __init__(self, *args, **kwargs):
        self.finalList = set()
    
    def crawlSite(self, linksList):
        for link in linksList:
            if link not in self.finalList:
                print link            
                self.finalList.add(link)
                childLinks = self.getAllUniqueLinks(link)
                length = len(childLinks)
                print 'Total links for this page: ' + str(length)
                self.crawlSite(childLinks)
    

    如果您想使用相同的实例从头开始,您只需确保您self.finalList = []

    编辑:通过将递归调用放在if 块中来修复代码。用了一套。另外,linksList 不需要是一个列表,只是一个可迭代对象,所以从for 循环中删除了list() 调用。 Set 由@Ray-Toal 建议

    【讨论】:

      【解决方案2】:

      您将在每次递归调用时清除 finalLinks 数组。

      需要的是一组您已经访问过的更全局的链接。每个递归调用都应该对这个全局列表有所贡献,否则,如果你的图有循环,你肯定会最终访问一个站点两次。

      更新:查看DFS on a graph using a python generator 中使用的漂亮模式。您的finalList 可以是一个参数,默认为[]。在每个递归调用中添加到此列表。另外,FWIW,考虑使用 set 而不是 list --- 它更快。

      【讨论】:

      • 不错的选择。但是,使用默认参数不如实例变量灵活,因为您无法清除它;如果要重新开始,则需要创建一个新实例。
      • @agf, true,但是带参数的方法是线程安全的。这是一个权衡。 :)
      猜你喜欢
      • 2020-06-12
      • 1970-01-01
      • 2014-08-12
      • 1970-01-01
      • 1970-01-01
      • 2017-08-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多