Python递归抓取网址

时间:2011-07-21 06:15:07

标签: python function recursion hyperlink web-crawler

我有这种方法,当提供链接列表时,将获得子链接,依此类推:

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相当新,可能不了解更复杂的方法。所以请解释你的思考过程。如果你不介意:)

2 个答案:

答案 0 :(得分:3)

你需要

finalList.extend(self.crawlSite(childLinks))

不仅仅是

self.crawlSite(childLinks)

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

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

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不一定是列表,只是一个可迭代对象,因此从list()循环中删除了for调用。套装由@ Ray-Toal

建议

答案 1 :(得分:2)

您正在清除每个递归调用的finalLinks数组。

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

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