2017-02-08 4 views
-1

Я учусь, написав паутину. Я пытаюсь получить список всех категорий бизнеса от allpages.com.Объекты в поиске заменяются

Ниже приводится вся моя программа. К сожалению, я не могу изолировать проблему, поэтому я вложил все это.

Если вы запустите эту программу, вы увидите, что в первую очередь она правильно загружает первую страницу и добавляет все выделенные категории в список категорий.

Однако, когда он загружает последующие страницы, кажется, испортил ссылку на родительскую категорию. Например. он неправильно вычисляет URL http://www.allpages.com/travel-tourism/political-ideological-organizations/, когда на самом деле political-ideological-organizations/ не является подкатегорией travel-tourism/. Копаясь в журналах, кажется, что они перезаписывают данные в объекте parent. Ошибка более выражена, тем больше рабочих есть.

Это работало немного лучше, прежде чем я начал передавать данные по ссылке на goroutine, но у меня была по существу та же проблема.

У меня есть несколько вопросов:

  1. Как я могу отладить это, не прибегая к собиранию через лога?
  2. Что случилось/почему это не работает и как его можно исправить?

    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) 
         }) 
    } 
    

Update Fixed - см комментарии ниже.

+0

могли бы вы предоставить гораздо меньше * * и автономный фрагмент кода, который демонстрирует эту проблему? Скорее всего, проблема скрыта в большом количестве шума. – Volker

+0

@ Волькер, к сожалению, я объяснил, что понятия не имею, что происходит, поэтому я не могу его конденсировать. – jbrown

+0

Как вы думаете, это хороший вопрос для SO? Будет ли ответ полезным и для других? – Volker

ответ

0

Looping над:

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

означало, что я посылал ссылку на временную переменную category к каналу, вместо фактического адреса памяти этого значения.

Я исправил это с помощью другого цикла:

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

     downloadChannel <- &categoriesValues[i] 
    } 
Смежные вопросы