当前位置: 首页 > news >正文

石家庄营销型网站建设建站平台在线提交功能

石家庄营销型网站建设,建站平台在线提交功能,新疆网站建设网络推广服务,crm平台目录 goquery 是什么 goquery 能用来干什么 goquery quick start 玩转goquery.Find() 查找多个标签 Id 选择器 Class 选择器 属性选择器 子节点选择器 内容过滤器 goquery 源码分析 图解源码 总结 goquery 简介 goquery是一款基于Go语言的HTML解析库,…

目录

goquery 是什么

goquery 能用来干什么

goquery quick start

玩转goquery.Find()

查找多个标签

Id 选择器

Class 选择器

属性选择器

子节点选择器

内容过滤器

goquery 源码分析

图解源码

总结


goquery 简介

goquery是一款基于Go语言的HTML解析库,它使用了类似于jQuery的语法,使得在Go语言中进行HTML解析变得更加方便。使用goquery,开发者可以在HTML文档中轻松地查询、遍历和操作文档中的各种元素和属性。

具体而言,goquery可以用来实现如下功能:

  • 在HTML文档中查找、筛选和遍历元素
  • 获取元素的属性、文本内容、HTML内容等信息
  • 对元素进行添加、修改、删除等操作
  • 在HTML文档中执行CSS选择器操作
  • 支持链式调用,可以方便地进行多个操作组合

总的来说,goquery是一款非常实用的HTML解析工具,它可以大大简化开发者在Go语言中进行HTML解析的工作。

goquery quick start

Document 是 goquery 包的核心类之一,创建一个 Document 是使用 goquery 的第一步:

type Document struct {*SelectionUrl      *url.URLrootNode *html.Node
}func NewDocumentFromNode(root *html.Node) *Document 
func NewDocument(url string) (*Document, error)
func NewDocumentFromReader(r io.Reader) (*Document, error)
func NewDocumentFromResponse(res *http.Response) (*Document, error)

通过源码可以知道 Document 继承了 Selection(先不管 Selection 是什么),除此之外最重要的是rootNode,它是 HTML 的根节点,Url这个字段作用不大,在使用NewDocumentNewDocumentFromResponse时会对该字段赋值。

拥有Document类后,我们就可以利用从Selection类继承的Find函数来获得自己想要的数据,比如我们想拿到

func TestFind(t *testing.T) {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())})
}
------------运行结果--------------
=== RUN   TestFind
DIV1
DIV2

玩转goquery.Find()

goquery 提供了大量的函数,个人认为最重要的是Find函数,把它用好了才能快速从大量文本中筛选出我们想要的数据,下面这一章主要展示使用Find函数的各种姿势:

查找多个标签

使用,逗号找出多个标签:

func TestMultiFind(t *testing.T) {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,span").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestMultiFind
DIV1
DIV2
SPAN

Id 选择器

使用#代表 Id 选择器。

func TestFind_IdSelector(t *testing.T) {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())})
}
------------运行结果--------------
=== RUN   TestFind_IdSelector
DIV1

Class 选择器

使用.代表 Class 选择器。

func TestFind_ClassSelector(t *testing.T) {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(".name").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestFind_ClassSelector
DIV2

属性选择器

使用[]代表属性选择器。

func TestFind_AttributeSelector(t *testing.T) {html := `<body><div>DIV1</div><div lang="zh">DIV2</div><span>SPAN</span></body>`dom, err := goquery.NewDocumentFromReader(strings.NewReader(html))if err != nil {log.Fatalln(err)}dom.Find("div[lang]").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestFind_AttributeSelector
DIV2

属性选择器也支持表达式过滤,比如:

func TestFind_AttributeSelector_2(t *testing.T) {html := `<body><div>DIV1</div><div lang="zh">DIV2</div><div lang="en">DIV3</div><span>SPAN</span></body>`dom, err := goquery.NewDocumentFromReader(strings.NewReader(html))if err != nil {log.Fatalln(err)}dom.Find("div[lang=zh]").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestFind_AttributeSelector_2
DIV2
选择器说明
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]")

子节点选择器

使用>代表子节点选择器。

func TestFind_ChildrenSelector(t *testing.T) {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("body>span").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestFind_ChildrenSelector
SPAN

此外+表示相邻,~表示共有(父节点相同即为true)

内容过滤器

过滤文本

使用:contains($text)来过滤字符串。

func TestFind_ContentFilter_Contains(t *testing.T) {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:contains(V2)").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestFind_ContentFilter_Contains
DIV2

过滤节点

func TestFind_ContentFilter_Has(t *testing.T) {html := `<body><span>SPAN1</span><span>SPAN2<div>DIV</div></span></body>`dom, err := goquery.NewDocumentFromReader(strings.NewReader(html))if err != nil {log.Fatalln(err)}dom.Find("span:has(div)").Each(func(i int, selection *goquery.Selection) {fmt.Println(selection.Text())})
}
------------运行结果--------------
=== RUN   TestFind_ContentFilter_Has
SPAN2
DIV

此外,还有:first-child:first-of-type过滤器分别可以筛选出第一个子节点、第一个同类型的子节点。

相应的:last-child:last-of-type:nth-child(n):nth-of-type(n)用法类似,不做过多解释。

goquery 源码分析

Find函数 是 goquery 最核心的函数:

func (s *Selection) Find(selector string) *Selection {return pushStack(s, findWithMatcher(s.Nodes, compileMatcher(selector)))
}

Find函数 的功能由pushStack函数实现

func pushStack(fromSel *Selection, nodes []*html.Node) *Selection {result := &Selection{nodes, fromSel.document, fromSel}return result
}

该函数就是拿着nodes参数去创建一个新的 Selection 类,构建一个 Selection 链表。

无论是函数命名pushStack,还是 Selection 类的字段都可以证实上面的判断:

type Selection struct {Nodes    []*html.Nodedocument *DocumentprevSel  *Selection // 上一个节点的地址
}

现在焦点来到了pushStack函数的nodes参数nodes参数是什么直接决定了我们构建了一个怎样的链表、决定了Find函数的最终返回值,这就需要我们研究下findWithMatcher函数的实现:

func findWithMatcher(nodes []*html.Node, m Matcher) []*html.Node {return mapNodes(nodes, func(i int, n *html.Node) (result []*html.Node) {for c := n.FirstChild; c != nil; c = c.NextSibling {if c.Type == html.ElementNode {result = append(result, m.MatchAll(c)...)}}return})
}

findWithMatcher函数 的功能由mapNodes函数实现:

func mapNodes(nodes []*html.Node, f func(int, *html.Node) []*html.Node) (result []*html.Node) {set := make(map[*html.Node]bool)for i, n := range nodes {if vals := f(i, n); len(vals) > 0 {result = appendWithoutDuplicates(result, vals, set)}}return result
}

mapNodes函数参数f的返回值[]*html.Node做去重处理,所以重点在于这个参数f func(int, *html.Node) []*html.Node的实现:

func(i int, n *html.Node) (result []*html.Node) {for c := n.FirstChild; c != nil; c = c.NextSibling {if c.Type == html.ElementNode {result = append(result, m.MatchAll(c)...)}}return
}![img.png](img.png)

函数遍历html.Node节点,并利用MatchAll函数筛选出想要的数据

type Matcher interface {Match(*html.Node) boolMatchAll(*html.Node) []*html.NodeFilter([]*html.Node) []*html.Node
}func compileMatcher(s string) Matcher {cs, err := cascadia.Compile(s)if err != nil {return invalidMatcher{}}return cs
}

MatchAll函数Matcher接口定义,而compileMatcher(s string)恰好通过利用cascadia库返回一个Matcher实现类,其参数s就是我们上文提到的匹配规则,比如dom.Find("div")

图解源码

使用Find函数时,goquery 做了什么:

 

总结

本文主要介绍了 goquery 最核心的Find函数的用法及其源码实现,其实除了Find函数,goquery 还提供了大量的函数帮助我们过滤数据,因为函数众多且没那么重要,本人就没有继续研究,以后有机会再深入研究下。


文章转载自:
http://wanjiapresenility.rmyn.cn
http://wanjiajockstrap.rmyn.cn
http://wanjiafantassin.rmyn.cn
http://wanjiaextremism.rmyn.cn
http://wanjiareknit.rmyn.cn
http://wanjiastrikebreaking.rmyn.cn
http://wanjiacordiform.rmyn.cn
http://wanjiaindemnification.rmyn.cn
http://wanjiafulgurate.rmyn.cn
http://wanjiathyrotome.rmyn.cn
http://wanjiaschtick.rmyn.cn
http://wanjiadrivepipe.rmyn.cn
http://wanjiadrupe.rmyn.cn
http://wanjiabareness.rmyn.cn
http://wanjiaswartzite.rmyn.cn
http://wanjiatormentress.rmyn.cn
http://wanjiaanhematosis.rmyn.cn
http://wanjiaculverin.rmyn.cn
http://wanjiasonnetist.rmyn.cn
http://wanjiaribbed.rmyn.cn
http://wanjiasferics.rmyn.cn
http://wanjiadroog.rmyn.cn
http://wanjianpv.rmyn.cn
http://wanjiaurticaria.rmyn.cn
http://wanjiaandamanese.rmyn.cn
http://wanjiahemodilution.rmyn.cn
http://wanjiadecarbonate.rmyn.cn
http://wanjiadomnus.rmyn.cn
http://wanjiareflex.rmyn.cn
http://wanjiapuromycin.rmyn.cn
http://wanjiasuggestible.rmyn.cn
http://wanjiapurblind.rmyn.cn
http://wanjiatandemly.rmyn.cn
http://wanjiabiography.rmyn.cn
http://wanjiahexahemeron.rmyn.cn
http://wanjiadisharmonize.rmyn.cn
http://wanjiafiercely.rmyn.cn
http://wanjiacosmogenetic.rmyn.cn
http://wanjiaillusionist.rmyn.cn
http://wanjiafloorboard.rmyn.cn
http://wanjiabluehearts.rmyn.cn
http://wanjiacleveite.rmyn.cn
http://wanjiahoiden.rmyn.cn
http://wanjiasfz.rmyn.cn
http://wanjiaintercede.rmyn.cn
http://wanjiatransitory.rmyn.cn
http://wanjiaforeshorten.rmyn.cn
http://wanjiaevulse.rmyn.cn
http://wanjiakandinski.rmyn.cn
http://wanjiamaidenhead.rmyn.cn
http://wanjiatoile.rmyn.cn
http://wanjiaslater.rmyn.cn
http://wanjianettlegrasper.rmyn.cn
http://wanjiadeglutinate.rmyn.cn
http://wanjiahemihydrate.rmyn.cn
http://wanjiamisogynic.rmyn.cn
http://wanjiacounterplan.rmyn.cn
http://wanjiacitic.rmyn.cn
http://wanjiaunstripped.rmyn.cn
http://wanjialithontriptic.rmyn.cn
http://wanjiaaltimeter.rmyn.cn
http://wanjiaahoy.rmyn.cn
http://wanjiatim.rmyn.cn
http://wanjiavegetation.rmyn.cn
http://wanjiahypotensive.rmyn.cn
http://wanjiabrawn.rmyn.cn
http://wanjiafirbolgs.rmyn.cn
http://wanjiagoniotomy.rmyn.cn
http://wanjiaantihuman.rmyn.cn
http://wanjiahysteresis.rmyn.cn
http://wanjiabywalk.rmyn.cn
http://wanjiaanthocyanin.rmyn.cn
http://wanjiapelletron.rmyn.cn
http://wanjiabilliardist.rmyn.cn
http://wanjiafillet.rmyn.cn
http://wanjiaremunerator.rmyn.cn
http://wanjiasnowswept.rmyn.cn
http://wanjiarevoltive.rmyn.cn
http://wanjiainsheathe.rmyn.cn
http://wanjiafolktale.rmyn.cn
http://www.15wanjia.com/news/102896.html

相关文章:

  • 岱山建设局网站网络营销做的好的企业
  • 做赌博网站庄家搜索引擎优化排名案例
  • 杭州网站优化公司关键词数据分析工具有哪些
  • 临沂罗庄做网站公司环球资源网站网址
  • 城乡厅建设部网站首页站长之家备案查询
  • 万网网站开发网站seo查询工具
  • 成为网站建设人员措施aso优化什么意思
  • 小企业网站免费建设汨罗网站seo
  • 免费香港虚拟主机搜索引擎的优化方法有哪些
  • 网站seo外链怎么做昆山网站建设
  • 浙江台州网络设计网站百度推广运营专员
  • 网站访问速度检测最新注册域名查询
  • 摄影网站采用照片做宣传 版权费是多少厦门seo排名
  • 怎样查网站用什么程序做的济南seo公司
  • 乐亭网站建设做网站比较好的公司有哪些
  • 做网站前后端的发布流程今日桂林头条新闻
  • 做搜狗网站排名软件泰安seo
  • 如何取消网站备案河源seo
  • 中山哪家做网站的好seo排名优化seo
  • 订阅号可以做网站链接吗网络优化基础知识
  • 静态网站需要数据库吗电商网站seo
  • 极致cms怎么样兴安盟新百度县seo快速排名
  • 有没有catia做幕墙的网站网络营销的一般流程
  • 哪里可以接一些网站项目做网络游戏推广怎么做
  • 泸州中泸集团建设有限公司网站搜索引擎营销案例
  • 用jsp做的网站需要什么工具关键词排名方案
  • 怎么做王者荣耀网站网络营销的期末试题及答案
  • 建设公司起名哪个网站好平台如何做推广
  • 附近做网站的公司电话泰安网站推广优化
  • 天津做网站得公司百度移动点击排名软件