golang实现类似jQuery的HTML解析与操作插件库GoQuery的使用

Golang实现类似jQuery的HTML解析与操作插件库GoQuery的使用

GoQuery简介

GoQuery是一个为Go语言提供的库,它带来了类似jQuery的语法和功能集。GoQuery基于Go的net/html包和CSS选择器库cascadia构建。

由于net/html解析器返回的是节点而不是完整的DOM树,因此jQuery的有状态操作函数(如height()、css()、detach())没有被包含在内。

安装

Go版本要求

  • 从v1.10.0版本开始,GoQuery需要Go 1.23+,因为使用了基于函数的迭代器
  • 对于v1.9.0版本,需要Go 1.18+,因为使用了泛型
  • 对于更早的GoQuery版本,由于net/html依赖关系,需要Go 1.1+

安装命令:

$ go get github.com/PuerkitoBio/goquery

(可选)运行单元测试:

$ cd $GOPATH/src/github.com/PuerkitoBio/goquery
$ go test

基本用法示例

下面是一个完整的GoQuery使用示例,展示了如何从网页中抓取并解析数据:

package main

import (
  "fmt"
  "log"
  "net/http"

  "github.com/PuerkitoBio/goquery"
)

func ExampleScrape() {
  // 请求HTML页面
  res, err := http.Get("http://metalsucks.net")
  if err != nil {
    log.Fatal(err)
  }
  defer res.Body.Close()
  if res.StatusCode != 200 {
    log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
  }

  // 加载HTML文档
  doc, err := goquery.NewDocumentFromReader(res.Body)
  if err != nil {
    log.Fatal(err)
  }

  // 查找评论项
  doc.Find(".left-content article .post-title").Each(func(i int, s *goquery.Selection) {
    // 对于每个找到的项目,获取标题
    title := s.Find("a").Text()
    fmt.Printf("Review %d: %s\n", i, title)
  })
}

func main() {
  ExampleScrape()
}

API设计

GoQuery暴露了两个结构体DocumentSelection,以及Matcher接口。与jQuery不同,GoQuery需要被告知要操作哪个HTML文档,这就是Document类型的作用。它保存根文档节点作为初始的Selection值来操作。

GoQuery遵循以下命名约定:

  • 当jQuery等效函数可以不带参数调用时,它与jQuery同名(如Prev()),带有选择器字符串参数的版本称为XxxFiltered()(如PrevFiltered())
  • 当jQuery等效函数需要一个参数时,使用与jQuery相同的名称作为选择器字符串版本(如Is())
  • 接受jQuery对象作为参数的签名在goquery中定义为XxxSelection()并接受*Selection对象作为参数(如FilterSelection())
  • 在jQuery中接受DOM元素作为参数的签名在goquery中定义为XxxNodes()并接受类型为*html.Node的可变参数(如FilterNodes())
  • 在jQuery中接受函数作为参数的签名在goquery中定义为XxxFunction()并接受函数作为参数(如FilterFunction())

注意事项

  • Cascadia的选择器不一定匹配jQuery(Sizzle)支持的所有选择器
  • 选择器的工作方式更像DOM的querySelectorAll,而不是jQuery的匹配器
  • 无效的选择器字符串编译为不匹配任何节点的Matcher

相关项目

  • Goq:基于goquery和结构标签的HTML反序列化和抓取库
  • andybalholm/cascadia:GoQuery使用的CSS选择器库
  • gocolly/colly:一个快速优雅的抓取框架
  • MontFerret/ferret:声明式网页抓取
  • Dataflow kit:面向Gopher的网页抓取框架
  • Geziyor:Go的快速网页爬取和抓取框架,支持JS渲染

支持项目

有多种方式可以支持这个项目:

  • 使用它、加星标、用它构建东西、传播它!
  • 提出改进项目的问题
  • 提交Pull请求
  • 赞助开发者

许可证

BSD 3-Clause许可证,与Go语言相同。Cascadia的许可证在这里。


更多关于golang实现类似jQuery的HTML解析与操作插件库GoQuery的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang实现类似jQuery的HTML解析与操作插件库GoQuery的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


GoQuery: Golang中的jQuery风格HTML解析库

GoQuery是一个流行的Golang库,它实现了类似jQuery的语法和功能,用于解析和操作HTML文档。下面我将详细介绍GoQuery的使用方法。

安装GoQuery

首先需要安装GoQuery及其依赖:

go get github.com/PuerkitoBio/goquery

基本用法

1. 从字符串创建文档

package main

import (
	"fmt"
	"github.com/PuerkitoBio/goquery"
	"log"
	"strings"
)

func main() {
	html := `<html>
		<head>
			<title>示例页面</title>
		</head>
		<body>
			<div id="content">
				<h1>标题</h1>
				<p class="intro">介绍段落</p>
				<ul>
					<li>项目1</li>
					<li>项目2</li>
					<li>项目3</li>
				</ul>
			</div>
		</body>
	</html>`

	// 从字符串创建文档
	doc, err := goquery.NewDocumentFromReader(strings.NewReader(html))
	if err != nil {
		log.Fatal(err)
	}

	// 查找标题
	title := doc.Find("title").Text()
	fmt.Println("标题:", title)
}

2. 从URL加载文档

func main() {
	// 从URL加载文档
	doc, err := goquery.NewDocument("http://example.com")
	if err != nil {
		log.Fatal(err)
	}

	// 查找所有链接
	doc.Find("a").Each(func(i int, s *goquery.Selection) {
		href, exists := s.Attr("href")
		if exists {
			fmt.Printf("链接 %d: %s\n", i+1, href)
		}
	})
}

常用选择器

GoQuery支持大部分jQuery选择器:

// ID选择器
doc.Find("#content")

// 类选择器
doc.Find(".intro")

// 元素选择器
doc.Find("h1")

// 属性选择器
doc.Find("input[name='email']")

// 后代选择器
doc.Find("div p") // div下的所有p元素

// 子元素选择器
doc.Find("ul > li") // ul的直接子元素li

// 相邻兄弟选择器
doc.Find("h1 + p") // 紧接在h1后的p元素

// 通用兄弟选择器
doc.Find("h1 ~ p") // h1之后的所有p兄弟元素

遍历和操作

1. 遍历元素

doc.Find("li").Each(func(i int, s *goquery.Selection) {
	fmt.Printf("项目 %d: %s\n", i+1, s.Text())
})

2. 获取和设置属性

// 获取属性
href, exists := doc.Find("a").Attr("href")

// 设置属性
doc.Find("img").SetAttr("alt", "描述文字")

3. 获取和修改内容

// 获取文本内容
text := doc.Find("p").Text()

// 获取HTML内容
html, _ := doc.Find("div").Html()

// 设置文本内容
doc.Find("h1").SetText("新标题")

// 设置HTML内容
doc.Find("div").SetHtml("<p>新内容</p>")

4. 添加和删除元素

// 追加元素
doc.Find("ul").Append("<li>新项目</li>")

// 前置元素
doc.Find("ul").Prepend("<li>第一个项目</li>")

// 删除元素
doc.Find(".ad").Remove()

// 保留元素但删除其内容
doc.Find("div").Empty()

过滤和查找

1. 过滤元素

// 按位置过滤
firstItem := doc.Find("li").First()
lastItem := doc.Find("li").Last()
thirdItem := doc.Find("li").Eq(2) // 索引从0开始

// 按条件过滤
evenItems := doc.Find("li").Even()  // 偶数位置
oddItems := doc.Find("li").Odd()    // 奇数位置
filtered := doc.Find("li").Filter(".active") // 带active类的li

2. 查找子元素

// 查找子元素
children := doc.Find("ul").Children()

// 查找后代元素
descendants := doc.Find("div").Find("p")

3. 查找父元素和祖先元素

// 直接父元素
parent := doc.Find("li").Parent()

// 所有祖先元素
parents := doc.Find("li").Parents()

// 最近的匹配祖先
closestDiv := doc.Find("span").Closest("div")

实际应用示例

1. 抓取网页内容

func scrapeExample() {
	doc, err := goquery.NewDocument("https://example.com")
	if err != nil {
		log.Fatal(err)
	}

	// 提取所有段落文本
	doc.Find("p").Each(func(i int, s *goquery.Selection) {
		fmt.Printf("段落 %d: %s\n", i+1, s.Text())
	})

	// 提取特定数据
	title := doc.Find("h1").Text()
	description, _ := doc.Find("meta[name='description']").Attr("content")
	fmt.Printf("标题: %s\n描述: %s\n", title, description)
}

2. 修改HTML文档

func modifyHTML() {
	html := `<div class="container"><p>原始内容</p></div>`
	doc, _ := goquery.NewDocumentFromReader(strings.NewReader(html))

	// 修改内容
	doc.Find(".container").SetHtml(`
		<h1>新标题</h1>
		<p>第一段</p>
		<p>第二段</p>
	`)

	// 添加类
	doc.Find("p").AddClass("text-paragraph")

	// 移除类
	doc.Find("h1").RemoveClass("old-class")

	// 获取修改后的HTML
	newHTML, _ := doc.Html()
	fmt.Println(newHTML)
}

注意事项

  1. GoQuery不是浏览器,不执行JavaScript
  2. 对于大型HTML文档,注意内存使用
  3. 网络请求可能需要设置超时和用户代理
  4. 处理动态内容可能需要结合其他工具如chromedp

GoQuery提供了强大而熟悉的jQuery风格API,使得在Go中处理HTML变得简单直观。无论是网页抓取还是HTML处理,它都是一个非常实用的工具。

回到顶部