2017-02-08 1 views
-1

Ich lerne gehen, indem Sie eine Webspinne schreiben. Ich versuche, eine Liste aller Geschäftskategorien von allpages.com zu erhalten.Objekte in gehen ersetzt werden

Unten ist mein gesamtes Programm. Leider kann ich das Problem nicht isolieren, also habe ich alles eingefügt.

Wenn Sie dieses Programm ausführen, sehen Sie zuerst, dass es die erste Seite korrekt herunterlädt und alle extrahierten Kategorien zur Liste der Kategorien hinzufügt.

Wenn es dann jedoch nachfolgende Seiten herunterlädt, scheint es den Verweis auf die übergeordnete Kategorie zu versauen. Z.B. es berechnet falsch die URL http://www.allpages.com/travel-tourism/political-ideological-organizations/, wenn tatsächlich political-ideological-organizations/ keine Unterkategorie von travel-tourism/ ist. Beim Durchforsten der Logs scheint es die Daten im Objekt parent zu überschreiben. Der Fehler ist umso ausgeprägter, je mehr Arbeiter dort sind.

Dies funktionierte ein wenig besser, bevor ich begann, Daten durch Verweis auf die Goroutine zu übergeben, aber ich hatte im Wesentlichen das gleiche Problem.

Ich habe mehrere Fragen:

  1. Wie kann ich das Debuggen ohne Kommissionierung durch Protokollzeilen zurückgreifen?
  2. Was ist falsch/warum funktioniert es nicht und wie kann es behoben werden?

    package main 
    
    import (
         "fmt" 
         "github.com/PuerkitoBio/goquery" 
         "log" 
         "strconv" 
         "strings" 
         "regexp" 
    ) 
    
    const domain = "http://www.allpages.com/" 
    const categoryPage = "category.html" 
    
    type Category struct { 
         url string 
         level uint 
         name string 
         entries int 
         parent *Category 
    } 
    
    type DownloadResult struct { 
         doc *goquery.Document 
         category *Category 
    } 
    
    const WORKERS = 2 
    const SEPARATOR = "§§§" 
    
    func main() { 
    
         allCategories := make([]Category, 0) 
    
         downloadChannel := make(chan *Category) 
         resultsChannel := make(chan *DownloadResult, 100) 
    
         for w := 1; w <= WORKERS; w++ { 
           go worker(downloadChannel, resultsChannel) 
         } 
    
         numRequests := 1 
         downloadChannel <- &Category{ domain + categoryPage, 0, "root", 0, nil } 
    
         for result := range resultsChannel { 
           var extractor func(doc *goquery.Document) []string 
    
           if result.category.level == 0 { 
             extractor = topLevelExtractor 
           } else if result.category.level == 1 { 
             extractor = secondLevelExtractor 
           } else { 
             extractor = thirdLevelExtractor 
           } 
    
           categories := extractCategories(result.doc, result.category, extractor) 
           allCategories = append(allCategories, *categories...) 
    
           //fmt.Printf("Appending categories: %v", *categories) 
    
           fmt.Printf("total categories = %d, total requests = %d\n", len(allCategories), numRequests) 
    
           for _, category := range *categories { 
             numRequests += 1 
             downloadChannel <- &category 
           } 
    
           // close the channels when there are no more jobs 
           if len(allCategories) > numRequests { 
             close(downloadChannel) 
             close(resultsChannel) 
           } 
         } 
    
         fmt.Println("Done") 
    } 
    
    func worker(downloadChannel <-chan *Category, results chan<- *DownloadResult) { 
         for target := range downloadChannel { 
           fmt.Printf("Downloading %v (addr %p) ...", target, &target) 
    
           doc, err := goquery.NewDocument(target.url) 
           if err != nil { 
             log.Fatal(err) 
             panic(err) 
           } 
    
           fmt.Print("done \n") 
    
           results <- &DownloadResult{doc, target} 
         } 
    } 
    
    func extractCategories(doc *goquery.Document, parent *Category, extractor func(doc *goquery.Document) []string) *[]Category { 
    
         numberRegex, _ := regexp.Compile("[0-9,]+") 
    
         log.Printf("Extracting subcategories for page %s\n", parent) 
    
         subCategories := extractor(doc) 
    
         categories := make([]Category, 0) 
    
         for _, subCategory := range subCategories { 
           log.Printf("Got subcategory=%s from parent=%s", subCategory, parent) 
           extracted := strings.Split(subCategory, SEPARATOR) 
    
           numberWithComma := numberRegex.FindString(extracted[2]) 
           number := strings.Replace(numberWithComma, ",", "", -1) 
    
           numRecords, err := strconv.Atoi(number) 
           if err != nil { 
             log.Fatal(err) 
             panic(err) 
           } 
    
           var category Category 
    
           level := parent.level + 1 
    
           if parent.level == 0 { 
             category = Category{ domain + extracted[1], level, extracted[0], numRecords, parent } 
           } else { 
             log.Printf("category URL=%s, parent=%s, parent=%v", extracted[1], parent.url, parent) 
             category = Category{ parent.url + extracted[1], level, extracted[0], numRecords, parent } 
           } 
    
           log.Printf("Appending category=%v (pointer=%p)", category, &category) 
    
           categories = append(categories, category) 
         } 
    
         return &categories 
    } 
    
    func topLevelExtractor(doc *goquery.Document) []string { 
         return doc.Find(".cat-listings-td .c-1s-2m-1-td1").Map(func(i int, s *goquery.Selection) string { 
           title := s.Find("a").Text() 
           url := s.Find("a").Map(func(x int, a *goquery.Selection) string { 
             v, _ := a.Attr("href") 
             return v 
           }) 
           records := s.Clone().Children().Remove().End().Text() 
    
           //log.Printf("Item %d: %s, %s - %s\n", i, title, records, url) 
    
           res := []string{title, url[0], records} 
           return strings.Join(res, SEPARATOR) 
         }) 
    } 
    
    func secondLevelExtractor(doc *goquery.Document) []string { 
         return doc.Find(".c-2m-3c-1-table .c-2m-3c-1-td1").Map(func(i int, s *goquery.Selection) string { 
           title := s.Find("a").Text() 
           url := s.Find("a").Map(func(x int, a *goquery.Selection) string { 
             v, _ := a.Attr("href") 
             return v 
           }) 
           records := s.Clone().Children().Remove().End().Text() 
    
           //log.Printf("Item %d: %s, %s - %s\n", i, title, records, url) 
    
           res := []string{title, url[0], records} 
           return strings.Join(res, SEPARATOR) 
         }) 
    } 
    
    func thirdLevelExtractor(doc *goquery.Document) []string { 
         return doc.Find(".c-2m-3c-1-table .c-2m-3c-1-td1").Map(func(i int, s *goquery.Selection) string { 
           title := s.Find("a").Text() 
           url := s.Find("a").Map(func(x int, a *goquery.Selection) string { 
             v, _ := a.Attr("href") 
             return v 
           }) 
           records := s.Clone().Children().Remove().End().Text() 
    
           //log.Printf("Item %d: %s, %s - %s\n", i, title, records, url) 
    
           res := []string{title, url[0], records} 
           return strings.Join(res, SEPARATOR) 
         }) 
    } 
    

aktualisieren Fest - siehe Kommentar unten.

+0

Könnten Sie einen viel * kleine * und Standalone-Schnipsel, die das Problem demonstriert? Wahrscheinlich ist das Problem in viel Lärm versteckt. – Volker

+0

@Volker leider wie ich erklärt habe ich keine Ahnung was los ist so kann ich es nicht verdichten. – jbrown

+0

Glaubst du, das ist eine gute Frage für SO? Wird eine Antwort auch für andere hilfreich sein? – Volker

Antwort

0

Looping über:

  for _, category := range *categories { 
        numRequests += 1 
        downloadChannel <- &category 
      } 

gemeint I wurde den Kanal einen Verweis auf die temporäre Variable category senden, anstelle der aktuellen Speicheradresse dieses Wertes.

ich dies habe feste eine andere Schleife unter Verwendung von:

for i := 0; i < len(*categories); i++ { 
     fmt.Printf("Queuing category: %v (%p)", categoriesValues[i], categoriesValues[i]) 

     downloadChannel <- &categoriesValues[i] 
    } 
Verwandte Themen