golang使用jQuery语法进行HTML声明式解析插件库goq的使用

Golang使用jQuery语法进行HTML声明式解析插件库goq的使用

goq是一个Golang库,允许用户使用类似jQuery的CSS选择器语法来声明式地将HTML解组到Go结构体中。

示例

下面是一个完整的示例,展示如何使用goq从GitHub页面提取标题和文件列表:

import (
	"log"
	"net/http"

	"astuart.co/goq"
)

// 定义结构体来表示GitHub文件名称表格
type example struct {
	Title string   `goquery:"h1"`  // 提取h1标签的文本
	Files []string `goquery:"table.files tbody tr.js-navigation-item td.content,text"` // 提取表格中的文件列表
}

func main() {
	// 获取GitHub页面
	res, err := http.Get("https://github.com/andrewstuart/goq")
	if err != nil {
		log.Fatal(err)
	}
	defer res.Body.Close()

	var ex example
	
	// 使用goq解析HTML到结构体
	err = goq.NewDecoder(res.Body).Decode(&ex)
	if err != nil {
		log.Fatal(err)
	}

	// 输出提取的结果
	log.Println(ex.Title, ex.Files)
}

使用说明

goq包的设计目的是让用户能够使用由CSS选择器组成的结构标签,声明式地将HTML解组到Go结构体中。

创建要解组到的结构体类型时,适用以下一般规则:

  1. 任何实现Unmarshaler接口的类型都将传递一个*html.Node切片,以便可以手动解组。这具有最高优先级。

  2. 任何结构字段都可以用goquery元数据注释,其形式为元素选择器后跟任意逗号分隔的"值选择器"。

  3. 值选择器可以是htmltext[someAttrName]之一:

    • htmltext将导致在*goquery.Selection上调用同名方法以获取值
    • [someAttrName]将导致调用*goquery.Selection.Attr("someAttrName")来获取值
  4. 如果没有给出值选择器,原始值类型将默认为结果节点的文本值。

  5. 对于映射,至少需要一个值选择器来确定映射键。键类型必须遵循适用于Go映射索引的规则以及这些解组规则。每个键的值将以与元素值相同的方式解组。

核心功能

解码HTML

func Unmarshal(bs []byte, v interface{}) error

Unmarshal接受一个字节切片和一个目标接口指针,并根据上述规则将文档解组到目标中。

解码选择器

func UnmarshalSelection(s *goquery.Selection, iface interface{}) error

UnmarshalSelection将goquery.Selection解组到适当注释的接口中。

自定义解码器

type Decoder struct {}

func NewDecoder(r io.Reader) *Decoder
func (d *Decoder) Decode(dest interface{}) error

Decoder实现了与encoding/xml和encoding/json相同的API,只是目前不支持适当的流解码,因为上游goquery不支持。

自定义解组

type Unmarshaler interface {
	UnmarshalHTML([]*html.Node) error
}

Unmarshaler允许自定义解组逻辑的实现。

错误处理

type CannotUnmarshalError struct {
	Err      error
	Val      string
	FldOrIdx interface{}
}

CannotUnmarshalError表示由goquery Unmarshaler返回的错误,并帮助用户以编程方式诊断其错误原因。

实用函数

func NodeSelector(nodes []*html.Node) *goquery.Selection

NodeSelector是一个快速实用函数,用于从*html.Node切片获取goquery.Selection。


更多关于golang使用jQuery语法进行HTML声明式解析插件库goq的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于golang使用jQuery语法进行HTML声明式解析插件库goq的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Goq: Go语言中的jQuery风格HTML解析库

Goq是一个Go语言的HTML解析库,它提供了类似jQuery的选择器语法,使得在Go中解析HTML文档变得更加简单直观。下面我将详细介绍goq的使用方法。

安装

首先安装goq库:

go get github.com/andrewstuart/goq

基本用法

1. 解析HTML文档

package main

import (
	"fmt"
	"github.com/andrewstuart/goq"
	"strings"
)

func main() {
	html := `
	<html>
		<body>
			<div class="content">
				<h1>标题</h1>
				<p>段落1</p>
				<p>段落2</p>
				<ul>
					<li>项目1</li>
					<li>项目2</li>
				</ul>
			</div>
		</body>
	</html>
	`

	// 解析HTML
	doc, err := goq.NewDoc(strings.NewReader(html))
	if err != nil {
		panic(err)
	}

	// 使用选择器
	title := doc.Find("h1").Text()
	fmt.Println("标题:", title) // 输出: 标题: 标题

	// 获取所有段落
	paragraphs := doc.Find("p")
	fmt.Println("段落数量:", paragraphs.Length()) // 输出: 段落数量: 2

	// 遍历元素
	paragraphs.Each(func(i int, sel *goq.Selection) {
		fmt.Printf("段落%d: %s\n", i+1, sel.Text())
	})
	// 输出:
	// 段落1: 段落1
	// 段落2: 段落2
}

2. 类似jQuery的选择器语法

// 类选择器
doc.Find(".content").Each(func(i int, sel *goq.Selection) {
    fmt.Println("找到class为content的元素:", sel.Text())
})

// ID选择器
doc.Find("#main").Each(func(i int, sel *goq.Selection) {
    fmt.Println("找到id为main的元素:", sel.Text())
})

// 属性选择器
doc.Find("a[href]").Each(func(i int, sel *goq.Selection) {
    href, _ := sel.Attr("href")
    fmt.Println("链接:", href)
})

// 后代选择器
doc.Find("div p").Each(func(i int, sel *goq.Selection) {
    fmt.Println("div下的p元素:", sel.Text())
})

3. 获取和修改属性

// 获取属性
doc.Find("a").Each(func(i int, sel *goq.Selection) {
    href, exists := sel.Attr("href")
    if exists {
        fmt.Println("链接地址:", href)
    }
})

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

4. 链式调用

text := doc.Find("div.content").
    Find("p").
    First().
    Text()
fmt.Println("第一个段落:", text)

5. 过滤和查找

// 过滤
doc.Find("li").Filter(func(i int, sel *goq.Selection) bool {
    return strings.Contains(sel.Text(), "2")
}).Each(func(i int, sel *goq.Selection) {
    fmt.Println("包含'2'的li:", sel.Text())
})

// 查找子元素
doc.Find("ul").Children().Each(func(i int, sel *goq.Selection) {
    fmt.Println("ul的子元素:", sel.Text())
})

实际应用示例:解析网页内容

package main

import (
	"fmt"
	"github.com/andrewstuart/goq"
	"net/http"
)

func main() {
	// 获取网页内容
	resp, err := http.Get("https://example.com")
	if err != nil {
		panic(err)
	}
	defer resp.Body.Close()

	// 解析HTML
	doc, err := goq.NewDoc(resp.Body)
	if err != nil {
		panic(err)
	}

	// 提取所有链接
	doc.Find("a").Each(func(i int, sel *goq.Selection) {
		href, _ := sel.Attr("href")
		text := sel.Text()
		fmt.Printf("链接%d: %s (%s)\n", i+1, text, href)
	})

	// 提取页面标题
	title := doc.Find("title").Text()
	fmt.Println("页面标题:", title)
}

注意事项

  1. goq不是真正的jQuery,它只实现了jQuery的部分选择器功能
  2. 对于大型HTML文档,性能可能不如标准库的html包
  3. 如果只需要简单解析,标准库的golang.org/x/net/html可能更高效

总结

goq为Go语言开发者提供了类似jQuery的HTML解析体验,使得从HTML文档中提取数据变得更加简单直观。它的链式调用和选择器语法让代码更易读易写,特别适合需要快速从HTML中提取数据的场景。

虽然它不如原生解析器高效,但在大多数常见用例中,这种简洁的API带来的开发效率提升往往比微小的性能差异更有价值。

回到顶部