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