Я учусь, написав паутину. Я пытаюсь получить список всех категорий бизнеса от allpages.com
.Объекты в поиске заменяются
Ниже приводится вся моя программа. К сожалению, я не могу изолировать проблему, поэтому я вложил все это.
Если вы запустите эту программу, вы увидите, что в первую очередь она правильно загружает первую страницу и добавляет все выделенные категории в список категорий.
Однако, когда он загружает последующие страницы, кажется, испортил ссылку на родительскую категорию. Например. он неправильно вычисляет URL http://www.allpages.com/travel-tourism/political-ideological-organizations/
, когда на самом деле political-ideological-organizations/
не является подкатегорией travel-tourism/
. Копаясь в журналах, кажется, что они перезаписывают данные в объекте parent
. Ошибка более выражена, тем больше рабочих есть.
Это работало немного лучше, прежде чем я начал передавать данные по ссылке на goroutine, но у меня была по существу та же проблема.
У меня есть несколько вопросов:
- Как я могу отладить это, не прибегая к собиранию через лога?
Что случилось/почему это не работает и как его можно исправить?
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 - см комментарии ниже.
могли бы вы предоставить гораздо меньше * * и автономный фрагмент кода, который демонстрирует эту проблему? Скорее всего, проблема скрыта в большом количестве шума. – Volker
@ Волькер, к сожалению, я объяснил, что понятия не имею, что происходит, поэтому я не могу его конденсировать. – jbrown
Как вы думаете, это хороший вопрос для SO? Будет ли ответ полезным и для других? – Volker