1. 程式人生 > >用Go來爬蟲 goquery使用

用Go來爬蟲 goquery使用

應工作內容需求,要爬取兩個網站的資料(至於是什麼網站,這裡就不透露了,哈哈,害怕被發現了封ip),這些資料是定期更新的。由於後端的所有服務都是用go寫的,於是不打算用python,還是想用go來完成這個需求,github裡搜了下,發現goquery這個爬蟲包用的人還挺多的,5000多個star,而且是BSD開源協議,於是毫不猶豫的拿來用了。

其次,分析這兩個網站的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

        })