【问题标题】:Golang web spider with pagination processing带有分页处理的 Golang 网络蜘蛛
【发布时间】:2018-01-10 23:39:03
【问题描述】:

我正在开发一个 golang 网络爬虫,它应该解析某些特定搜索引擎上的搜索结果。主要困难 - 并发解析,或者更确切地说,处理分页,例如 ← Previous 1 2 3 4 5 ... 34 Next →。除了递归爬取分页结果外,一切都很好。看我的代码:

package main

import (
    "bufio"
    "errors"
    "fmt"
    "net"
    "strings"

    "github.com/antchfx/htmlquery"
    "golang.org/x/net/html"
)

type Spider struct {
    HandledUrls []string
}

func NewSpider(url string) *Spider {
    // ...
}

func requestProvider(request string) string {
    // Everything is good here
}

func connectProvider(url string) net.Conn {
    // Also works
}

// getContents makes request to search engine and gets response body
func getContents(request string) *html.Node {
    // ...
}

// CheckResult controls empty search results
func checkResult(node *html.Node) bool {
    // ...
}

func (s *Spider) checkVisited(url string) bool {
    // ...
}

// Here is the problems
func (s *Spider) Crawl(url string, channelDone chan bool, channelBody chan *html.Node) {
    body := getContents(url)

    defer func() {
        channelDone <- true
    }()

    if checkResult(body) == false {
        err := errors.New("Nothing found there")
        ErrFatal(err)
    }

    channelBody <- body
    s.HandledUrls = append(s.HandledUrls, url)
    fmt.Println("Handled ", url)

    newUrls := s.getPagination(body)

    for _, u := range newUrls {
        fmt.Println(u)
    }

    for i, newurl := range newUrls {
        if s.checkVisited(newurl) == false {
            fmt.Println(i)
            go s.Crawl(newurl, channelDone, channelBody)
        }
    }
}

func (s *Spider) getPagination(node *html.Node) []string {
    // ...
}

func main() {
    request := requestProvider(*requestFlag)
    channelBody := make(chan *html.Node, 120)
    channelDone := make(chan bool)

    var parsedHosts []*Host

    s := NewSpider(request)

    go s.Crawl(request, channelDone, channelBody)

    for {
        select {
        case recievedNode := <-channelBody:
             // ...

            for _, h := range newHosts {
                 parsedHosts = append(parsedHosts, h)
                 fmt.Println("added", h.HostUrl)
            }

        case <-channelDone:
            fmt.Println("Jobs finished")
        }

        break
   }
}

它总是返回只返回首页,没有分页。相同的 GetPagination(...) 效果很好。请告诉我,我的错误在哪里。 希望谷歌翻译是正确的。

【问题讨论】:

    标签: go concurrency pagination web-crawler screen-scraping


    【解决方案1】:

    问题可能是 main 在所有 goroutine 完成之前退出。

    首先,break 在select 语句之后有一个break,它会在第一次读取通道后非编码地运行。这可确保 main 函数在您第一次通过 channelBody 发送内容后返回。

    其次,在这里使用channelDone 不是正确的方法。最惯用的方法是使用sync.WaitGroup。在启动每个 goroutine 之前,使用WG.Add(1) 并将defer 替换为defer WG.Done();在main 中,使用WG.Wait()。请注意,您应该使用指针来引用WaitGroup。你可以阅读更多here。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多