在 goquery 中,`class="text title"` 表示元素同时拥有 `text` 和 `title` 两个独立类名,需用 `.text.title`(无空格、连续点号)语法匹配,而非 `.text title`(后者为后代选择器)。理解 html class 属性的多值语义是正确使用 css 选择器的关键。
HTML 规范中,class 属性是一个以空格分隔的类名列表,而非单一字符串。因此 实际表示该元素同时属于 text 类和 title 类。goquery 基于标准 CSS 选择器语法解析,其行为与浏览器 DevTools 中的 document.querySelectorAll() 完全一致:
以下为完整可运行示例,演示正确用法及常见误区:
package main
import (
"fmt"
"strings"
"github.com/PuerkitoBio/goquery"
)
func main() {
html := strings.NewReader(`
Go
totally kicks
hacks
立即学习“前端免费学习笔记(深入)”;
`)
doc, _ := goquery.NewDocumentFromReader(html)
// ✅ 正确:查找同时拥有 "text" 和 "title" 类的元素
fmt.Println("=== .text.title ===")
doc.Find(".text.title").Each(func(i int, s *goquery.Selection) {
class, _ := s.Attr("class")
fmt.Printf("class=%q, text=%q\n", class, s.Text())
// 输出:class="text title", text="Go "
})
// ✅ 正确:仅查找含 "title" 类的元素(宽松匹配)
fmt.Println("\n=== .title ===")
doc.Find(".t
itle").Each(func(i int, s *goquery.Selection) {
class, _ := s.Attr("class")
fmt.Printf("class=%q, text=%q\n", class, s.Text())
// 输出:class="text title", text="Go "
})
// ❌ 错误:".text title" 会查找 .text 元素内部的 .title 元素(本例中无匹配)
fmt.Println("\n=== .text title (后代选择器,无结果) ===")
doc.Find(".text title").Each(func(i int, s *goquery.Selection) {
fmt.Println("UNEXPECTED MATCH:", s.Text())
})
}⚠️ 注意事项:
doc.Find("*").Filter(func(i int, s *goquery.Selection) bool {
class, exists := s.Attr("class")
return exists && strings.Contains(class, "text")
})掌握这一基本原理后,你就能准确构造复杂选择器(如 .btn.btn-primary.disabled)并避免因空格引发的静默匹配失败。