应工作内容需求,要爬取两个网站的数据(至于是什么网站,这里就不透露了,哈哈,害怕被发现了封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
})