title: goquery的使用
tags: go,goquery,爬虫
author: Clown95
本文参考 飞雪无痕 的 《golang goquery selector(选择器) 示例大全》
概述
相信很多小伙伴对爬虫有着很大的兴趣,今天我们就来说下go语言的爬虫利器goquery
,有使用过jquery
的小伙伴是不是看着这个很眼熟?goquery类似jquery,它是jquery的go版本实现,使用它,可以很方便的对HTML进行处理。
goquery是基于 Go net/htm包和css选择器库 cascadia。由于net/htm解析器返回的是DOM节点,而不是完整的DOM树,因此, jQuery的状态操作函数没有实现(像height(), css(), detach)
注意:goquery只支持utf-8编码,其他编码需要转换。
安装
在终端输入命令安装goquery。
go get github.com/PuerkitoBio/goquery
简单使用
我们首先通过一个小例子来介绍goqery。
func main() {
html := `<html>
<body>
<h1 id="title">春晓</h1>
<p class="content1">
春眠不觉晓,
处处闻啼鸟。
夜来风雨声,
花落知多少。
</p>
</body>
</html>
`
dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
if err!=nil{
log.Fatalln(err)
}
dom.Find("p").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
}
得到结果:
春眠不觉晓,
处处闻啼鸟。
夜来风雨声,
花落知多少。
NewDocumentFromReader()
返回了一个*Document和error。Document代表一个将要被操作的HTML文档。
Find()
是获取当前匹配元素集中每个元素的子代,参数是x选择器
,它返回一个包含这些匹配元素的新选择对象。在例子中我们使用的是元素选择器P
,它会帮我们匹配出所有的p标签
。
Each()
是迭代器,它会循环遍历选择的节点,它的参数是一个匿名函数,匿名函数拥有2个参数,一个是元素的索引位置
,还有一个就是选择的结果集
匹配到的内容都在它的里面。
Text()
则是获取匹配元素集中的文本内容。
选择器
上面的例子中,我们使用了元素选择器
,goquery跟jquery一样都支持很多选择器,我们简单的介绍下常用的选择器:
- 基于HTML Element 元素的选择器
就是基于a,p等这些HTML的基本元素进行选择。
使用方法 :使用语法为 dom.Find("p")
,匹配文档中所有的p标签。
- ID 选择器
ID选择器是我们使用最频繁的,假如我们有2个p元素,其实我们只需要其中的一个,那么我们只需要给这个标记一个唯一的id即可,这样我们就可以使用id选择器,精确定位了。
使用方法 :id选择器以#
开头,紧跟着元素id的值,使用语法为
dom.Find("#title")
,匹配文档中所有的 id=title的内容
如果多个标签的ID都是title,我们可以指定某一个标签,如dom.Find("p#title")
- Class选择器
类选择跟ID选择器一样都是使用很频繁的,我们可以通过类选择器快速筛选到需要的内容。
使用方法 : id选择器以.
开头,紧跟着元素class的值,使用语法为dom.Find(".content1")
,匹配文档中所有的 id=title的元素。
类选择权器跟ID选择器一样,也可以指定某一个标签dom.Find("div.content1")
- 属性选择器
一个HTML元素都有自己的属性以及属性值,所以我们也可以通过属性和值筛选元素。
使用方法 :我们可以通过元素的属性和属性值来筛选数据,使用语法为dom.Find("p[class=content1]
,匹配文档中所有的 p标签的class属性是content1的元素。
当然我们这里以class属性为例,还可以用其他属性,比如href等很多,自定义属性也是可以的。
刚刚我们使用的是完全相等
的匹配方式,属性选择器还要很多匹配方式。
选择器 | 说明 |
---|---|
Find(“div[my]“) | 筛选含有my属性的div元素 |
Find(“div[my=zh]“) | 筛选my属性为zh的div元素 |
Find(“div[my!=zh]“) | 筛选my属性不等于zh的div元素 |
Find(“div[my¦=zh]“) | 筛选my属性为zh或者zh-开头的div元素 |
Find(“div[my*=zh]“) | 筛选my属性包含zh这个字符串的div元素 |
Find(“div[my~=zh]“) | 筛选my属性包含zh这个单词的div元素,单词以空格分开的 |
Find(“div[my$=zh]“) | 筛选my属性以zh结尾的div元素,区分大小写 |
Find(“div[my^=zh]“) | 筛选my属性以zh开头的div元素,区分大小写 |
- parent > child选择器
筛选出某个元素下的子元素。
使用方法:使用>
符号连接,使用语法 dom.Find("div>p")
, 筛选div标签下的p标签
- element + next 相邻选择器
如果要筛选的元素没有规律,但是该元素的上一个元素有规律,我们就可以使用这种下一个相邻选择器来进行选择。
如:
<div>
<p my="a">a</p>
<p>b</p>
<p>c</p>
<div>
我想筛选出b
所在的标签
使用方法:dom.Find("p[my=a]+p")
筛选出p标签属性my的值为a的相邻p标签。
- element~next 兄弟选择器
有时候我们需要筛选同一父元素下,不相邻的标签,可以使用兄弟选择器
比如我想筛选出 b 和c 所在标签
使用方法:dom.Find("p[my=a]~p")
,筛选出p标签属性my的值为a的兄弟p标签。
过滤器
有时候我们选择出来的结果,并不是我们心目中的最优结果,我们希望对其进行过滤。
- :contains过滤器
筛选出的元素要包含指定的文本,比如我想筛选出包含a的p标签
使用方法:dom.Find("p:contains(a)")
,筛选出内容包含a的p标签
Find(":has(selector)")和contains差不多,只不过这个是包含的是元素节点。
此外还有Find(":empty")表示筛选出的元素都不能有子元素(包括文本元素),只筛选那些不包含任何子元素的元素。
- :first-child过滤器 和:first-of-type过滤器
筛选出的元素要是他们的父元素的第一个子元素,如果不是,则不会被筛选出来。
使用方法:语法为Find("p:first-child"),筛选出第一个p标签
:first-child选择器限制的比较死,必须得是第一个子元素,如果该元素前有其他在前面,就不能用:first-child了,这时候:first-of-type就派上用场了,它要求只要是这个类型的第一个就可以。
- :last-child 和:last-of-type过滤器
这两个正好和上面的:first-child、:first-of-type相反
- :nth-child(n) 过滤器
筛选出的元素是其父元素的第n个元素,n以1开始。所以我们可以知道:first-child和:nth-child(1)是相等的。通过指定n,我们就很灵活的筛选出我们需要的元素。
- :nth-of-type(n) 过滤器
:nth-of-type(n)和 :nth-child(n) 类似,只不过它表示的是同类型元素的第n个,所以:nth-of-type(1) 和 :first-of-type是相等的。
- :nth-last-child(n) 和:nth-last-of-type(n) 过滤器
这两个和上面的类似,只不过是倒序开始计算的,最后一个元素被当成了第一个
- :only-child 过滤器 和 :only-of-type 过滤器
筛选出父元素中,只有它自己的一个的元素。
常用方法
- 类似函数的位置操作
- Find(selection) *Selection //根据选择器查找节点集
- 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 //根据起始位置获取子节点集
- 循环遍历选择的节点
Each(f func(int, *Selection)) *Selection //遍历
EachWithBreak(f func(int, *Selection) bool) *Selection //可中断遍历
Map(f func(int, *Selection) string) (result []string) //返回字符串数组
- 检测或获取节点属性值
Attr(), RemoveAttr(), SetAttr() //获取,移除,设置属性的值
AddClass(), HasClass(), RemoveClass(), ToggleClass()
Html() //获取该节点的html
Length() //返回该Selection的元素个数
Text() //获取该节点的文本值
- 在文档树之间来回跳转(常用的查找节点方法)
Children() //返回selection中各个节点下的孩子节点
Contents() //获取当前节点下的所有节点
Find() //查找获取当前匹配的元素
Next() //下一个元素
Prev() //上一个元素
总结
goquery 是解析HTML网页必备的利器,在爬虫抓取网页的过程中,灵活的使用goquery不同的选择器,可以让我们的抓取工作事半功倍,大大提升爬虫的效率。
有疑问加站长微信联系(非本文作者)