golang使用XPath表达式从HTML文档提取数据插件库htmlquery的使用
Golang使用XPath表达式从HTML文档提取数据插件库htmlquery的使用
概述
htmlquery
是一个用于HTML的XPath查询包,允许您通过XPath表达式从HTML文档中提取数据或评估内容。
htmlquery
内置了基于LRU的查询对象缓存功能,该功能会缓存最近使用的XPath查询字符串。启用查询缓存可以避免每次查询时重新编译XPath表达式。
安装
go get github.com/antchfx/htmlquery
快速入门
基本查询示例
// 查询所有A元素
nodes, err := htmlquery.QueryAll(doc, "//a")
if err != nil {
panic(`not a valid XPath expression.`)
}
// 查询所有带有href属性的A元素
list := htmlquery.Find(doc, "//a[@href]")
// 查询第三个A元素
a := htmlquery.FindOne(doc, "//a[3]")
加载HTML文档
// 从URL加载HTML文档
doc, err := htmlquery.LoadURL("http://example.com/")
// 从文件加载HTML文档
filePath := "/home/user/sample.html"
doc, err := htmlquery.LoadDoc(filePath)
// 从字符串加载HTML文档
s := `<html>....</html>`
doc, err := htmlquery.Parse(strings.NewReader(s))
提取属性值
// 查找所有A元素的href属性
list := htmlquery.Find(doc, "//a/@href")
for _, n := range list{
fmt.Println(htmlquery.InnerText(n)) // 输出@href值
}
// 查找A元素下的img子元素并打印src属性
a := htmlquery.FindOne(doc, "//a")
img := htmlquery.FindOne(a, "//img")
fmt.Println(htmlquery.SelectAttr(img, "src")) // 输出@src值
计算元素数量
expr, _ := xpath.Compile("count(//img)")
v := expr.Evaluate(htmlquery.CreateXPathNavigator(doc)).(float64)
fmt.Printf("total count is %f", v)
完整示例
func main() {
// 从URL加载HTML文档
doc, err := htmlquery.LoadURL("https://www.bing.com/search?q=golang")
if err != nil {
panic(err)
}
// 查找所有新闻项
list, err := htmlquery.QueryAll(doc, "//ol/li")
if err != nil {
panic(err)
}
// 遍历结果并提取链接和文本
for i, n := range list {
a := htmlquery.FindOne(n, "//a")
if a != nil {
fmt.Printf("%d %s(%s)\n", i, htmlquery.InnerText(a), htmlquery.SelectAttr(a, "href"))
}
}
}
常见问题
Find()
vs QueryAll()
有什么区别?
Find
和QueryAll
都做相同的事情,搜索所有匹配的HTML节点。如果给出错误的XPath查询,Find
会引发panic,而QueryAll
会返回错误。
可以保存查询表达式对象以供下次查询使用吗?
是的,可以使用QuerySelector
和QuerySelectorAll
方法,它们接受查询表达式对象。缓存查询表达式对象(或重用)可以避免重新编译XPath查询表达式,提高查询性能。
如何禁用缓存?
htmlquery.DisableSelectorCache = true
缓存性能对比
goos: windows
goarch: amd64
pkg: github.com/antchfx/htmlquery
BenchmarkSelectorCache-4 20000000 55.2 ns/op
BenchmarkDisableSelectorCache-4 500000 3162 ns/op
支持的XPath语法
htmlquery
支持XPath 1.0/2.0语法。
更多关于golang使用XPath表达式从HTML文档提取数据插件库htmlquery的使用的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于golang使用XPath表达式从HTML文档提取数据插件库htmlquery的使用的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
使用htmlquery库在Golang中提取HTML数据
htmlquery是一个基于XPath的HTML解析库,它允许你使用XPath表达式从HTML文档中提取数据。以下是详细的使用指南和示例代码。
安装htmlquery
首先需要安装htmlquery库:
go get github.com/antchfx/htmlquery
基本使用方法
1. 加载HTML文档
package main
import (
"fmt"
"log"
"strings"
"github.com/antchfx/htmlquery"
"golang.org/x/net/html"
)
func main() {
// 从字符串加载HTML
htmlStr := `
<html>
<head>
<title>示例页面</title>
</head>
<body>
<div class="content">
<h1>标题</h1>
<p>段落1</p>
<p>段落2</p>
<ul>
<li>项目1</li>
<li>项目2</li>
</ul>
</div>
</body>
</html>`
doc, err := htmlquery.Parse(strings.NewReader(htmlStr))
if err != nil {
log.Fatal(err)
}
// 从URL加载HTML
// doc, err := htmlquery.LoadURL("http://example.com")
// if err != nil {
// log.Fatal(err)
// }
// 从文件加载HTML
// doc, err := htmlquery.LoadDoc("example.html")
// if err != nil {
// log.Fatal(err)
// }
}
2. 使用XPath查询
// 查询单个节点
title := htmlquery.FindOne(doc, "//title/text()")
fmt.Println(htmlquery.InnerText(title)) // 输出: 示例页面
// 查询多个节点
paragraphs := htmlquery.Find(doc, "//p")
for _, p := range paragraphs {
fmt.Println(htmlquery.InnerText(p))
}
// 输出:
// 段落1
// 段落2
3. 常用XPath表达式示例
// 获取所有li元素的文本
items := htmlquery.Find(doc, "//ul/li")
for i, item := range items {
fmt.Printf("项目%d: %s\n", i+1, htmlquery.InnerText(item))
}
// 获取特定class的元素
contentDiv := htmlquery.FindOne(doc, "//div[@class='content']")
fmt.Println(htmlquery.OutputHTML(contentDiv, true))
// 获取属性值
h1 := htmlquery.FindOne(doc, "//h1")
fmt.Println(htmlquery.SelectAttr(h1, "class")) // 获取class属性
高级用法
1. 处理相对路径
contentDiv := htmlquery.FindOne(doc, "//div[@class='content']")
if contentDiv != nil {
// 在contentDiv下相对查找
h1 := htmlquery.FindOne(contentDiv, "./h1")
fmt.Println(htmlquery.InnerText(h1)) // 输出: 标题
}
2. 使用谓词
// 获取第一个p元素
firstP := htmlquery.FindOne(doc, "//p[1]")
fmt.Println(htmlquery.InnerText(firstP)) // 输出: 段落1
// 获取最后一个li元素
lastLi := htmlquery.FindOne(doc, "//li[last()]")
fmt.Println(htmlquery.InnerText(lastLi)) // 输出: 项目2
3. 提取链接
htmlStr := `
<html>
<body>
<a href="/page1">链接1</a>
<a href="/page2">链接2</a>
</body>
</html>`
doc, _ := htmlquery.Parse(strings.NewReader(htmlStr))
links := htmlquery.Find(doc, "//a/@href")
for _, link := range links {
fmt.Println(htmlquery.InnerText(link)) // 输出: /page1 和 /page2
}
实际应用示例
示例1:提取新闻标题和链接
func scrapeNews() {
doc, err := htmlquery.LoadURL("https://news.example.com")
if err != nil {
log.Fatal(err)
}
// 假设新闻条目在class为news-item的div中,标题在h2,链接在a标签
nodes := htmlquery.Find(doc, "//div[@class='news-item']")
for _, node := range nodes {
title := htmlquery.FindOne(node, "./h2/a/text()")
link := htmlquery.FindOne(node, "./h2/a/@href")
if title != nil && link != nil {
fmt.Printf("标题: %s\n链接: %s\n\n",
htmlquery.InnerText(title),
htmlquery.InnerText(link))
}
}
}
示例2:提取表格数据
func scrapeTable() {
htmlStr := `
<table>
<tr><th>姓名</th><th>年龄</th></tr>
<tr><td>张三</td><td>25</td></tr>
<tr><td>李四</td><td>30</td></tr>
</table>`
doc, _ := htmlquery.Parse(strings.NewReader(htmlStr))
rows := htmlquery.Find(doc, "//tr[position()>1]") // 跳过表头
for _, row := range rows {
name := htmlquery.FindOne(row, "./td[1]")
age := htmlquery.FindOne(row, "./td[2]")
fmt.Printf("%s: %s岁\n",
htmlquery.InnerText(name),
htmlquery.InnerText(age))
}
}
注意事项
- htmlquery基于标准XPath 1.0,不支持XPath 2.0及更高版本的功能
- 对于大型HTML文档,考虑使用
htmlquery.FindEach
来减少内存使用 - 处理动态加载的内容时,可能需要结合其他工具如chromedp
- XPath表达式对大小写敏感
htmlquery提供了一种在Golang中处理HTML文档的便捷方式,特别适合需要精确提取特定数据的场景。通过合理使用XPath表达式,可以高效地从复杂HTML结构中提取所需信息。