golang goquery selector选择器使用示例大全

目录
  • 引言
  • 基于HTML Element 元素的选择器
  • ID 选择器
  • Element ID 选择器
  • Class选择器
  • Element Class 选择器
  • 属性选择器
  • parent>child选择器
  • prev+next相邻选择器
  • prev~next选择器
  • 内容过滤器
  • :first-child过滤器
  • :first-of-type过滤器
  • :last-child 和 :last-of-type过滤器
  • :nth-child(n) 过滤器
  • :nth-of-type(n) 过滤器
  • nth-last-child(n) 和:nth-last-of-type(n) 过滤器
  • :only-child 过滤器
  • :only-of-type 过滤器
  • 选择器或(|)运算
  • 小结

引言

最近研究Go爬虫相关的知识,使用到goquery这个库比较多,尤其是对爬取到的HTML进行选择和查找匹配的内容时,goquery的选择器使用尤其多,而且还有很多不常用但又很有用的选择器,这里总结下,以供参考。

如果大家以前做过前端开发,对jquery不会陌生,goquery类似jquery,它是jquery的go版本实现。使用它,可以很方便的对HTML进行处理。

基于HTML Element 元素的选择器

这个比较简单,就是基于a,p等这些HTML的基本元素进行选择,这种直接使用Element名称作为选择器即可。

比如dom.Find("div")

func main() {
	html := `<body>
				<div>DIV1</div>
				<div>DIV2</div>
				<span>SPAN</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})
}

以上示例,可以把div元素筛选出来,而body,span并不会被筛选。

ID 选择器

这个是使用频次最多的,类似于上面的例子,有两个div元素,其实我们只需要其中的一个,那么我们只需要给这个标记一个唯一的id即可,这样我们就可以使用id选择器,精确定位了。

func main() {
	html := `<body>
				<div id="div1">DIV1</div>
				<div>DIV2</div>
				<span>SPAN</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("#div1").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})
}

Element ID 选择器

id选择器以#开头,紧跟着元素id的值,使用语法为dom.Find(#id),后面的例子我会简写为Find(#id),大家知道这是代表goquery选择器的即可。

如果有相同的ID,但是它们又分别属于不同的HTML元素怎么办?有好办法,和Element结合起来。比如我们筛选元素为div,并且iddiv1的元素,就可以使用Find(div#div1)这样的筛选器进行筛选。

所以这类筛选器的语法为Find(element#id),这是常用的组合方法,比如后面讲的过滤器也可以采用这种方式组合使用。

Class选择器

class也是HTML中常用的属性,我们可以通过class选择器来快速的筛选需要的HTML元素,它的用法和ID选择器类似,为Find(".class")

func main() {
	html := `<body>
				<div id="div1">DIV1</div>
				<div class="name">DIV2</div>
				<span>SPAN</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find(".name").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})
}

以上示例中,就筛选出来classname的这个div元素。

Element Class 选择器

class选择器和id选择器一样,也可以结合着HTML元素使用,他们的语法也类似Find(element.class),这样就可以筛选特定element、并且指定class的元素。

属性选择器

一个HTML元素都有自己的属性以及属性值,所以我们也可以通过属性和值筛选元素。

func main() {
	html := `<body>
				<div>DIV1</div>
				<div class="name">DIV2</div>
				<span>SPAN</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div[class]").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})
}

示例中我们通过div[class]这个选择器,筛选出Element为div并且有class这个属性的,所以第一个div没有被筛选到。

刚刚上面这个示例是采用是否存在某个属性为筛选器,同理,我们可以筛选出属性为某个值的元素。

    dom.Find("div[class=name]").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})

这样我们就可以筛选出class这个属性值为namediv元素。

当然我们这里以class属性为例,还可以用其他属性,比如href等很多,自定义属性也是可以的。

除了完全相等,还有其他匹配方式,使用方式类似,这里统一列举下,不再举例

选择器 说明
Find(“div[lang]”) 筛选含有lang属性的div元素
Find(“div[lang=zh]”) 筛选lang属性为zh的div元素
Find(“div[lang!=zh]”) 筛选lang属性不等于zh的div元素
Find(“div[lang¦=zh]”) 筛选lang属性为zh或者zh-开头的div元素
Find(“div[lang*=zh]”) 筛选lang属性包含zh这个字符串的div元素
Find(“div[lang~=zh]”) 筛选lang属性包含zh这个单词的div元素,单词以空格分开的
Find(“div[lang$=zh]”) 筛选lang属性以zh结尾的div元素,区分大小写
Find(“div[lang^=zh]”) 筛选lang属性以zh开头的div元素,区分大小写

以上是属性筛选器的用法,都是以一个属性筛选器为例,当然你也可以使用多个属性筛选器组合使用,比如: Find("div[id][lang=zh]"),用多个中括号连起来即可。当有多个属性筛选器的时候,要同时满足这些筛选器的元素才能被筛选出来。

parent>child选择器

如果我们想筛选出某个元素下符合条件的子元素,我们就可以使用子元素筛选器,它的语法为Find("parent>child"),表示筛选parent这个父元素下,符合child这个条件的最直接(一级)的子元素。

func main() {
	html := `<body>
				<div lang="ZH">DIV1</div>
				<div lang="zh-cn">DIV2</div>
				<div lang="en">DIV3</div>
				<span>
					<div>DIV4</div>
				</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("body>div").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})
}

以上示例,筛选出body这个父元素下,符合条件的最直接的子元素div,结果是DIV1、DIV2、DIV3,虽然DIV4也是body的子元素,但不是一级的,所以不会被筛选到。

那么问题来了,我就是想把DIV4也筛选出来怎么办?就是要筛选body下所有的div元素,不管是一级、二级还是N级。有办法的,goquery考虑到了,只需要把大于号(>)改为空格就好了。比如上面的例子,改为如下选择器即可。

    dom.Find("body div").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})

prev+next相邻选择器

假设我们要筛选的元素没有规律,但是该元素的上一个元素有规律,我们就可以使用这种下一个相邻选择器来进行选择。

func main() {
	html := `<body>
				<div lang="zh">DIV1</div>
				<p>P1</p>
				<div lang="zh-cn">DIV2</div>
				<div lang="en">DIV3</div>
				<span>
					<div>DIV4</div>
				</span>
				<p>P2</p>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div[lang=zh]+p").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})
}

这个示例演示了这种用法,我们想选择<p>P1</p>这个元素,但是没啥规律,我们发现它前面的<div lang="zh">DIV1</div>很有规律,可以选择,所以我们就可以采用Find("div[lang=zh]+p")达到选择P元素的目的。

这种选择器的语法是("prev+next"),中间是一个加号(+),+号前后也是选择器。

prev~next选择器

有相邻就有兄弟,兄弟选择器就不一定要求相邻了,只要他们共有一个父元素就可以。

	dom.Find("div[lang=zh]~p").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})

刚刚的例子,只需要把+号换成~号,就可以把P2也筛选出来,因为P2P1DIV1都是兄弟。

兄弟选择器的语法是("prev~next"),也就是相邻选择器的+换成了~

内容过滤器

有时候我们使用选择器选择出来后后,希望再过滤一下,这时候就用到过滤器了,过滤器有很多,我们先讲内容过滤器这一种。

	dom.Find("div:contains(DIV2)").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})

Find(":contains(text)")表示筛选出的元素要包含指定的文本,我们例子中要求选择出的div元素要包含DIV2文本,那么只有一个DIV2元素满足要求。

此外还有Find(":empty")表示筛选出的元素都不能有子元素(包括文本元素),只筛选那些不包含任何子元素的元素。

Find(":has(selector)")contains差不多,只不过这个是包含的是元素节点。

    dom.Find("span:has(div)").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Text())
	})

以上示例表示筛选出包含div元素的span节点。

:first-child过滤器

:first-child过滤器,语法为Find(":first-child"),表示筛选出的元素要是他们的父元素的第一个子元素,如果不是,则不会被筛选出来。

func main() {
	html := `<body>
				<div lang="zh">DIV1</div>
				<p>P1</p>
				<div lang="zh-cn">DIV2</div>
				<div lang="en">DIV3</div>
				<span>
					<div style="display:none;">DIV4</div>
					<div>DIV5</div>
				</span>
				<p>P2</p>
				<div></div>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div:first-child").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Html())
	})
}

以上例子中,我们使用Find("div")会筛选出所有的div元素,但是我们加了:first-child后,就只有DIV1DIV4了,因为只有这两个是他们父元素的第一个子元素,其他的DIV都不满足。

:first-of-type过滤器

:first-child选择器限制的比较死,必须得是第一个子元素,如果该元素前有其他在前面,就不能用:first-child了,这时候:first-of-type就派上用场了,它要求只要是这个类型的第一个就可以,我们把上面的例子微调下。

func main() {
	html := `<body>
				<div lang="zh">DIV1</div>
				<p>P1</p>
				<div lang="zh-cn">DIV2</div>
				<div lang="en">DIV3</div>
				<span>
					<p>P2</p>
					<div>DIV5</div>
				</span>
				<div></div>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div:first-of-type").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Html())
	})
}

改动很简单,把原来的DIV4换成了P2,如果我们还使用:first-child,DIV5是不能被筛选出来的,因为它不是第一个子元素,它前面还有一个P2。这时候我们使用:first-of-type就可以达到目的,因为它要求是同类型第一个就可以。DIV5就是这个div类型的第一个元素,P2不是div类型,被忽略。

:last-child 和 :last-of-type过滤器

这两个正好和上面的:first-child:first-of-type相反,表示最后一个,这里不再举例,大家可以自己试试。

:nth-child(n) 过滤器

这个表示筛选出的元素是其父元素的第n个元素,n以1开始。所以我们可以知道:first-child:nth-child(1)是相等的。通过指定n,我们就很灵活的筛选出我们需要的元素。

func main() {
	html := `<body>
				<div lang="zh">DIV1</div>
				<p>P1</p>
				<div lang="zh-cn">DIV2</div>
				<div lang="en">DIV3</div>
				<span>
					<p>P2</p>
					<div>DIV5</div>
				</span>
				<div></div>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div:nth-child(3)").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Html())
	})
}

这个示例会筛选出DIV2,因为DIV2是其父元素body的第三个子元素。

: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 过滤器

Find(":only-child") 过滤器,从字面上看,可以猜测出来,它表示筛选的元素,在其父元素中,只有它自己,它的父元素没有其他子元素,才会被匹配筛选出来。

func main() {
	html := `<body>
				<div lang="zh">DIV1</div>
				<span>
					<div>DIV5</div>
				</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div:only-child").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Html())
	})
}

示例中DIV5就可以被筛选出来,因为它是它的父元素span达到唯一子元素,但DIV1就不是,所以不能呗筛选出来。

:only-of-type 过滤器

上面的例子,如果想筛选出DIV1怎么办?可以使用Find(":only-of-type"),因为它是它的父元素中,唯一的div元素,这就是:only-of-type过滤器所要做的,同类型元素只要只有一个,就可以被筛选出来。大家把上面的例子改成:only-of-type试试,看看是否有DIV1

选择器或(|)运算

如果我们想同时筛选出div,span等元素怎么办?这时候可以采用多个选择器进行组合使用,并且以逗号(,)分割,Find("selector1, selector2, selectorN")表示,只要满足其中一个选择器就可以被筛选出来,也就是选择器的或(|)运算操作。

func main() {
	html := `<body>
				<div lang="zh">DIV1</div>
				<span>
					<div>DIV5</div>
				</span>
			</body>
			`
	dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
	if err!=nil{
		log.Fatalln(err)
	}
	dom.Find("div,span").Each(func(i int, selection *goquery.Selection) {
		fmt.Println(selection.Html())
	})
}

小结

goquery 是解析HTML网页必备的利器,在爬虫抓取网页的过程中,灵活的使用goquery不同的选择器,可以让我们的抓取工作事半功倍,大大提升爬虫的效率。

以上就是golang goquery selector选择器使用示例大全的详细内容,更多关于golang goquery selector选择器的资料请关注我们其它相关文章!

(0)

相关推荐

  • Go使用select切换协程入门详解

    目录 前言 程序示例 select 特性预览 管道读写 总结 前言 在 Go 中,可以通过关键字 select 来完成从不同的并发执行的协程中获取值,它和 switch 控制语句非常相似,也被称作通信开关:它的行为像是“你准备好了吗”的轮询机制: select 监听进入通道的数据,也可以是用通道发送值的时候. select 是 Go 在语言层面提供的多路 I/O 复用机制,用于检测多个管道是否就绪(即可读或可写),其特性与管道息息相关. 语法格式: select { case u:= <- ch

  • golang解析网页利器goquery的使用方法

    前言 本文主要给大家介绍了关于golang解析网页利器goquery使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. java里用Jsoup,nodejs里用cheerio,都可以相当方便的解析网页,在golang语言里也找到了一个网页解析的利器,相当的好用,选择器跟jQuery一样 安装 go get github.com/PuerkitoBio/goquery 使用 其实就是项目的readme.md里的demo package main import ( "f

  • Go语言select语句用法示例

    目录 用法 使用场景 实现收发功能 注意事项 用法 多个通道 Channel 中信息的发送和接受处理的专用的语句—select 语句.select 语句会阻塞,直到其中的一个发送/接收操作准备好.select 语句和 switch 语句有点相似,但 select 语句在被执行时会选择执行其中的一个分支,且选择分支的方法完全是不相同的. ch1 = make(chan string) ch2 = make(chan string) ch1 <- "server1" ch2 <

  • go语言编程之select信道处理示例详解

    目录 select信道处理 fibonacci数列监听 select监听协程 select信道处理 注意:有default就不会阻塞 package main func main() { var chan1 = make(chan int) var chan2 = make(chan int) select { case <-chan1: // 如果chan1成功读到数据,则进行该case处理语句 case chan2: // 如果chan2成功读到数据,则进行该case处理语句 default

  • Go 语言选择器实例教程

    目录 引言 选择器的深度 有效选择器 唯一性+最浅深度 空指针 接口 一个特殊情况 在 hood 下 引言 在 Go 语言中,表达式 foo.bar 可能表示两件事.如果 foo 是一个包名,那么表达式就是一个所谓的限定标识符,用来引用包 foo 中的导出的标识符.由于它只用来处理导出的标识符,bar 必须以大写字母开头(译注:如果首字母大写,则可以被其他的包访问:如果首字母小写,则只能在本包中使用): package foo import "fmt" func Foo() { fmt

  • golang goquery selector选择器使用示例大全

    目录 引言 基于HTML Element 元素的选择器 ID 选择器 Element ID 选择器 Class选择器 Element Class 选择器 属性选择器 parent>child选择器 prev+next相邻选择器 prev~next选择器 内容过滤器 :first-child过滤器 :first-of-type过滤器 :last-child 和 :last-of-type过滤器 :nth-child(n) 过滤器 :nth-of-type(n) 过滤器 nth-last-child

  • ImageView 实现Android colorPikcer 选择器的示例代码

    本文介绍了ImageView 实现Android colorPikcer 选择器的示例代码,分享给大家,具体如下: Android colorPikcer 选择器 环形的ColorPicker,主要思路是: Color 选在放在ImageView 的background上面,根据点击的位置判断选择的颜色. 重写onTouch,在onTouch 里面判断点击点的颜色. 根据当前选择的颜色设置图片的src. 获取Bitmap 在 ColorPickerView 构造函数中初始化 Bitmap.因为g

  • Android 仿京东商城底部布局的选择效果(Selector 选择器的实现)

    京东商城的底部布局的选择效果看上去很复杂,其实很简单,这主要是要感谢 selector 选择器,本文将讲解仿照京东商城的底部布局的选择效果,如何实现 selector 选择器,在不同的状态下,给 view 设置不同的背景. 京东商城底部布局的选择效果如下. View主要的几种状态 主要状态有8种,设置状态的代码以及相应的含义如下. android:state_pressed = "true/false" //true表示按下状态,false表示非按下状态. android:state_

  • GoLang 中的随机数的示例代码

    随机数我们都知道,就是计算机通过某种算法,"随机"的生成一个数字.很多编程语言都有内置的方法来生成随机数,那么 GoLang 中是怎样一种情况呢? 伪随机数 我们都知道"随机数"在现实生活中的概念,可能你随手抛一个硬币,就可以说其结果是随机的,但是在计算机中要确定一个"随机数"真的是"随机数",那可是有标准的,不是你随随便便说是就是. 根据密码学原理,要想对一个"随机数"进行随机性检验有以下几个标准: 统计

  • Golang Cron 定时任务的实现示例

    开门见山写一个 package main import ( "fmt" "github.com/robfig/cron" "log" "strings" "time" ) func CronTask() { log.Println("******** ******* *******") } func CronTest() { log.Println("Starting Cron

  • golang之JWT实现的示例代码

    什么是JSON Web Token? JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于在各方之间以JSON方式安全地传输信息.由于此信息是经过数字签名的,因此可以被验证和信任.可以使用秘密(使用HMAC算法)或使用RSA或ECDSA的公钥/私钥对对JWT进行签名. 直白的讲jwt就是一种用户认证(区别于session.cookie)的解决方案. 出现的背景 众所周知,在jwt出现之前,我们已经有session.cookie来解决用户登

  • Maven镜像地址配置示例大全

    最近在准备项目架构时,虽然自己已经又了私服,通过私服进行仓库的管理,但是由于网速的限制原因,又想在项目环境迁移时可以快速的构建并启动或者快速更新,之前项目开发的工作中,使用了一个国外的一个仓库,拉取了一些坏的包,导致了一些异常,后来搞了好几天才解决掉(解决办法:当然是更换仓库镜像地址咯!!!),所以花费了些时间收集并整理了这些 maven镜像地址. Maven 镜像地址大全 1.阿里的镜像地址 <mirror>     <id>alimaven</id>     <

  • golang 进度条功能实现示例

    最近在做一个需求,功能很简单,就是开发一个轻量级客户端,将一个指定文件中的内容通过 TCP 发送到服务器.由于该文件特别大,有可能到达100G的数量级,因此处理起来会比较慢,为了给用户提供比较友好的展示界面,因此,在其中加入了进度条显示功能. 在这里,说一下我在实现该进度条功能时的一些思路. 成果演示 先看一下最终的成品效果展示: 该进度条一共分三部分组成,第一部分是主体进度条,第二部分是百分比,第三部分是当前完成的数据和总数据的一个动态展示. 源码分析 由于是要在终端上打印出进度条的效果,因此

  • 基于gin的golang web开发:路由示例详解

    Gin是一个用Golang编写的HTTP网络框架.它的特点是类似于Martini的API,性能更好.在golang web开发领域是一个非常热门的web框架. 启动一个Gin web服务器 使用下面的命令安装Gin go get -u github.com/gin-gonic/gin 在代码里添加依赖 import "github.com/gin-gonic/gin" 快速启动一个Gin服务器的代码如下 package main import "github.com/gin-

  • js实现类选择器和name属性选择器的示例步骤

    jQuery的出现,大大的提升了我们操作dom的效率,使得我们的开发更上一层楼,如jQuery的选择器就是一个很强大的功能,它包含了类选择器.id选择器.属性选择器.元素选择器.层级选择器.内容筛选选择器等等,很是方便快捷,并且这些选择器的兼容性都很好,可以说操作dom使用jq选择器一时爽,一直使用一直爽!只是,目前Vue.React.Angular三大框架的出现大大降低了JQuery的使用频率,而且JQuery在操作dom和绑定数据时确实存在一定的性能问题和各种坑,但依旧不可抹杀jq在操作do

随机推荐