2011-07-21 43 views
0

我有這樣的方法,當一個鏈接列表供應將得到子鏈接等等等等是:Python的遞歸爬行對於網址

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

您正在清除finalLinks數組在每次遞歸調用。

需要的是您已經訪問的更全局的鏈接集。每次遞歸調用都應該爲這個全局列表做出貢獻,否則,如果你的圖形有循環,你肯定會最終訪問一個網站兩次。

更新:查看DFS on a graph using a python generator中使用的漂亮圖案。您的finalList可以是一個參數,默認爲[]。在每次遞歸調用中添加到此列表中。此外,FWIW,考慮一個set而不是list ---它更快。

+0

好的替代品。雖然使用默認參數比實例變量更不靈活,因爲您無法清除它;如果你想重新開始,你需要創建一個新的實例。 – agf

+0

@agf,true,但參數的方法是線程安全的。這是一個折衷。 :) –

3

你需要

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()調用。設置由@ Ray-Toal建議