2011-07-29 18 views
0

我想爲所有的網頁刮一個頁面,並將它們放在字典中。我用字典創建了一個類。但我似乎無法添加元素。爲什麼這個f#代碼中的成員字典總是空的?

type crawler = 

    new()= {} 
    member this.urls = new Dictionary<string,string>() 
    member this.start (url : string)= 
     let hw = new HtmlWeb() 
     let doc = hw.Load(url) 
     let docNode = doc.DocumentNode 
     let links = docNode.SelectNodes(".//a") 

     for aLink in links do 
      let href = aLink.GetAttributeValue("href"," ") 
      if href.StartsWith("http://") && href.EndsWith(".html") then 
       this.urls.Add(href, href) 

爲什麼字典是空的?

回答

5

因爲這裏的url是每次調用都返回新字典的屬性。

type Crawler() = 
    let urls = new Dictionary<string,string>() 
    member this.Urls = urls 
    member this.Start (url : string)=   
     let hw = new HtmlWeb()   
     let doc = hw.Load(url)   
     let docNode = doc.DocumentNode   
     let links = docNode.SelectNodes(".//a")   
     for aLink in links do    
      let href = aLink.GetAttributeValue("href"," ")    
      if href.StartsWith("http://") && href.EndsWith(".html") then    
       urls.Add(href, href) 
+0

什麼是最好的選擇? – unj2

+1

他的代碼是解決方案。它不是每次都調用屬性get函數,而是使用字段(它類似於類級別的值)。它也可以在沒有__。Urls屬性的情況下工作(注意他沒有使用它)。 –

3

這不是你的問題,但如果你有興趣參加一個功能更強大的方法,下面是做這件事:現在

type Crawler = 
    { Urls : Set<string> } 

[<CompilationRepresentation(CompilationRepresentationFlags.ModuleSuffix)>] 
module Crawler = 

    [<CompiledName("Start")>] 
    let start crawler (url:string) = 
    let { Urls = oldUrls } = crawler 
    let newUrls = 
     HtmlWeb().Load(url).DocumentNode.SelectNodes(".//a") 
     |> Seq.cast<HtmlNode> 
     |> Seq.choose (fun link -> 
     match link.GetAttributeValue("href"," ") with 
     | href when href.StartsWith("http://") && href.EndsWith(".html") -> Some href 
     | _ -> None) 
     |> Set.ofSeq 
     |> Set.union oldUrls 
    { crawler with Urls = newUrls } 

您的數據和行爲是分開的。 Crawler是不可變的記錄類型。 start接受Crawler,並返回一個新的更新的URL列表。我將Dictionary替換爲Set,因爲鍵和值是相同的;淘汰未使用的let綁定,並在某些模式匹配中進行偷窺。這在C#中也應該有一個相對友好的界面。

+0

哇,我不知道你可以從模式匹配那樣的記錄類型中提取值! – Benjol

相關問題