用Go来爬虫 goquery使用

应工作内容需求,要爬取两个网站的数据(至于是什么网站,这里就不透露了,哈哈,害怕被发现了封ip),这些数据是定期更新的。由于后端的所有服务都是用go写的,于是不打算用python,还是想用go来完成这个需求,github里搜了下,发现goquery这个爬虫包用的人还挺多的,5000多个star,而且是BSD开源协议,于是毫不犹豫的拿来用了。

首先,go get https://github.com/PuerkitoBio/goquery

其次,分析这两个网站的DOM布局,发现还是比较好爬的。

先来一波goquery的常见用法:

Document 代表一个HTML文档,

type Document struct {
    *Selection  
    Url      *url.URL
    rootNode *html.Node
    }

Document 继承了Selection 类型,因此,Document 可以直接使用 Selection 类型的方法。
而Selection 则对应的是dom节点集合

type Selection struct {
    Nodes    []*html.Node
    document *Document
    prevSel  *Selection
}

根据url初始化

  func NewDocument(url string) (*Document, error) {
   // Load the URL
   res, e := http.Get(url)  
   if e != nil {
      return nil, e
   }
   return NewDocumentFromResponse(res)
}

Selection类型提供的方法,这些方法是页面解析最重要,最核心的方法

1)类似函数的位置操作

  • Eq(index int) *Selection //根据索引获取某个节点集

  • First() *Selection //获取第一个子节点集

  • Last() *Selection //获取最后一个子节点集

  • Next() *Selection //获取下一个兄弟节点集

  • NextAll() *Selection //获取后面所有兄弟节点集

  • Prev() *Selection //前一个兄弟节点集

  • Get(index int) *html.Node //根据索引获取一个节点

  • Index() int //返回选择对象中第一个元素的位置

  • Slice(start, end int) *Selection //根据起始位置获取子节点集

2)循环遍历选择的节点

  • Each(f func(int, *Selection)) *Selection //遍历

  • EachWithBreak(f func(int, *Selection) bool) *Selection //可中断遍历

  • Map(f func(int, *Selection) string) (result []string) //返回字符串数组

3)检测或获取节点属性值

  • Attr(), RemoveAttr(), SetAttr() //获取,移除,设置属性的值

  • AddClass(), HasClass(), RemoveClass(), ToggleClass()

  • Html() //获取该节点的html

  • Length() //返回该Selection的元素个数

  • Text() //获取该节点的文本值

4)在文档树之间来回跳转(常用的查找节点方法)

  • Children() //返回selection中各个节点下的孩子节点

  • Contents() //获取当前节点下的所有节点

  • Find() //查找获取当前匹配的元素

  • Next() //下一个元素

  • Prev() //上一个元素

介绍完毕,开始使用:

第一个网站:

doc, err := goquery.NewDocument(url)
    if err != nil {
        logger.Error("get document error:", err)
        return
    }
    doc.Find(".first").EachWithBreak(func(i int, s *goquery.Selection) bool {
        //d := s.Eq(0).Find("td")//每个first tr标签下面就只有一个td节点集
        //fmt.Println(s.Children().Text())

        //遍历孩子节点,需要中断跳出,所以用了EachWithBreak
        s.Children().EachWithBreak(func(j int, selection *goquery.Selection) bool {
            //fmt.Println(selection.Text())

            //获取内容
            str := selection.Text()
            currencyIndexList = append(currencyIndexList, util.FindNumbers(str))
            if j == 5 {
                return false
            }
            return true
        })

        if i == 0 {
            return false
        }
        return true

    })
    return

第二个网站

doc, err := goquery.NewDocument(url + "?name=" + value)
        if err != nil {
            logger.Error("get document error:", err)
            return
        }
        var priceList []string
        doc.Find(".SPD_main").Children().EachWithBreak(func(i int, s *goquery.Selection) bool {
            s.Children().EachWithBreak(func(j int, selection *goquery.Selection) bool {

                tr := selection.Children().First().Next()

                tr.Children().Each(func(k int, trselection *goquery.Selection) {
                    str := trselection.Text()
                    priceList = append(priceList, str)
                })

                if j == 0 {
                    return false
                }
                return true
            })
            if i == 0 {
                return false
            }
            return true

        })

你可能感兴趣的:(golang)