2011-07-29 1 views
0

Je veux gratter une page pour toutes les URL et les mettre dans le dictionnaire. J'ai créé une classe avec un dictionnaire. Mais je n'arrive pas à ajouter des éléments.Pourquoi le dictionnaire membre de ce code f # est-il toujours vide?

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) 

Pourquoi les URL du dictionnaire sont-elles vides?

Répondre

5

car les URL sont la propriété qui retourne un nouveau dictionnaire à chaque appel.

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

quelle serait la meilleure alternative? – unj2

+1

Son code est la solution. Au lieu d'appeler la fonction get function à chaque fois, elle utilise le champ (qui est comme une valeur de niveau classe). Cela fonctionnerait également sans la propriété __. Urls (remarquez qu'il ne l'utilise pas). –

3

Ce ne fut pas votre question, mais si vous êtes intéressé à prendre une approche plus fonctionnelle, voici une façon de le faire:

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 } 

Vos données et comportements sont maintenant séparés. Crawler est un type d'enregistrement immuable. start accepte un Crawler et renvoie un nouveau avec la liste mise à jour des URL. J'ai remplacé Dictionary par Set, puisque les clés et les valeurs sont les mêmes; éliminé let liaisons inutilisées, et glissé dans un motif correspondant. Cela devrait avoir une interface relativement conviviale en C# aussi.

+0

Wow, je ne savais pas que vous pouviez extraire des valeurs à partir de types d'enregistrements avec des motifs correspondants! – Benjol

Questions connexes