//参考博客 https://www.flysnow.org/2018/01/20/golang-goquery-examples-selector.html#%E9%80%89%E6%8B%A9%E5%99%A8%E6%88%96%E8%BF%90%E7%AE%97
package main
import (
"fmt"
"github.com/PuerkitoBio/goquery"
"log"
"strings"
)
func HtmlElement() {
html := `<body>
<div>DIV1</div>
<div>DIV2</div>
<div id="aabb">DIV3</div>
<p id="aabb">DIV4</p>
<div class="name">DIV5</div>
<div lang="aabb" class="name">DIV6</div>
<span>
<div>DIV7</div>
</span>
<p>PDIV</p>
<p></p>
<p>PDIV1</p>
</body>
`
dom,err:=goquery.NewDocumentFromReader(strings.NewReader(html))
if err!=nil{
log.Fatalln(err)
}
//基于HTML Element 元素的选择器
//匹配标签为div的元素,Each() 是迭代器,它会循环遍历选择的节点
dom.Find("div").Each(func(i int, selection *goquery.Selection) {
//Text() 则是获取匹配元素集中的文本内容
fmt.Println(selection.Text())
})
//ID 选择器
//选取 id="aabb" 的元素
dom.Find("#aabb").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//Element ID 选择器
//有相同的ID,但是它们又分别属于不同的HTML元素
//选取 <p id="aabb">DIV4</p>
dom.Find("p#aabb").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//Class选择器
//选取 <div class="name">DIV5</div>
dom.Find(".name").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//Element Class 选择器
//筛选出Element为div并且有class这个属性元素
dom.Find("div[class]").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//筛选出属性为某个值的元素
dom.Find("div[class=name]").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//多个属性筛选器组合使用
dom.Find("div[lang=aabb][class=name]").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
/*其他匹配方式示例
选择器 说明
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元素,区分大小写
*/
//parent>child选择器
//筛选出某个元素下符合条件的子元素
//筛选parent这个父元素下,符合child这个条件的最直接(一级)的子元素
//语法 Find("parent>child")
//不会筛选 <span> <div>DIV7</div> </span>,不是一级子元素
dom.Find("body>div").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//筛选出某个元素下所有的子元素
//将 Find("parent>child") 中 > 改为空格
dom.Find("body div").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//prev+next相邻选择器
//筛选的元素没有规律,上一个元素有规律
//使用下一个相邻选择器来进行选择
//选取 <p>PDIV</p>
dom.Find("span+p").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//选取 <p id="aabb">DIV4</p>
dom.Find("div[id=aabb]+p").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//prev~next选择器
//不一定要求相邻了,共有一个父元素
//选择共同父元素 p,选取 <p>PDIV</p>
dom.Find("p[id=aabb]~p").Each(func(i int, selection *goquery.Selection) {
fmt.Println("p[id=aabb]~p")
fmt.Println(selection.Text())
})
//内容过滤器
//语法 Find(":contains(text)") 筛选出的元素要包含指定的文本
dom.Find("div:contains(DIV2)").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//语法 Find(":empty") 筛选出的元素都不能有子元素(包括文本元素)
//筛选出来的为空
dom.Find("p:empty").Each(func(i int, selection *goquery.Selection) {
fmt.Println("筛选出的元素都不能有子元素")
fmt.Println(selection.Text())
})
//Find(":has(selector)")和contains差不多,只不过这个是包含的是元素节点。
dom.Find("span:has(div)").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Text())
})
//:first-child过滤器
//语法 Find(":first-child")
//筛选出的元素要是他们的父元素的第一个子元素,如果不是,则不会被筛选出来。
//筛选 DIV1 DIV4,均为父元素的第一个元素
dom.Find("div:first-child").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//:first-of-type过滤器
//该类型的第一个元素,限制比 :first-child 宽松
//若 :first-child 筛选元素前面加一个元素,则筛选不出,使用 :first-of-type 则可以
//比如将 <span> <div>DIV7</div> </span> 改成 <span> <p>DIVDIV</p> <div>DIV7</div> </span>
// :first-child 筛选不出 DIV7 ,:first-of-type 则可以筛选出
dom.Find("div:first-of-type").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//:last-child 和 :last-of-type过滤器
//表示与 first-child、:first-of-type相反,表示最后一个
dom.Find("div:last-child").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
dom.Find("div:last-of-type").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//:nth-child(n) 过滤器
//筛选出的元素是其父元素的第n个元素,n以1开始
//筛选出 DIV2
dom.Find("div:nth-child(2)").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//:nth-of-type(n) 过滤器
//:nth-of-type(n)和 :nth-child(n) 类似,只不过它表示的是同类型元素的第n个,
//所以:nth-of-type(1) 和 :first-of-type是相等的
dom.Find("div:nth-of-type(2)").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//nth-last-child(n) 和:nth-last-of-type(n) 过滤器
//倒序开始计算的,最后一个元素被当成了第一个
dom.Find("p:nth-last-child(1)").Each(func(i int, selection *goquery.Selection) {
fmt.Println("p:nth-last-child(1)")
fmt.Println(selection.Html())
})
dom.Find("div:nth-last-of-type(2)").Each(func(i int, selection *goquery.Selection) {
fmt.Println("div:nth-last-of-type(2)")
fmt.Println(selection.Html())
})
//:only-child 过滤器
//语法 Find(":only-child")
//父元素除了被筛选出来的元素,没有其他的子元素
dom.Find("div:only-child").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//:only-of-type 过滤器
//同类型元素只要只有一个,就可以被筛选出来
dom.Find("div:only-of-type").Each(func(i int, selection *goquery.Selection) {
fmt.Println(selection.Html())
})
//选择器或(|)运算
//多个选择器进行组合使用,并且以逗号(,)分割
//只要满足其中一个选择器就可以被筛选出来,也就是选择器的或(|)运算操作。
//语法 Find("selector1, selector2, selectorN")
dom.Find("div,span").Each(func(i int, selection *goquery.Selection) {
fmt.Println("div,span")
fmt.Println(selection.Html())
})
}
func main() {
HtmlElement()
}