Skip to content

包函数

包级函数适合一次性调用场景,内部使用 sync.Pool 复用 Processor,无需手动管理生命周期。注意:池化 Processor 已禁用缓存与审计保留;需要缓存/统计/审计请用 html.New 创建独立 Processor。

内部机制

池化设计

包函数底层维护一个 sync.Pool,在每次调用之间复用 Processor 实例,避免重复分配。关键实现细节:

  • 池化配置禁用缓存:池用的配置(poolCfg)以 DefaultConfig() 为基础,但显式置零三个缓存相关字段——MaxCacheEntries=0CacheTTL=0CacheCleanup=0。因此包函数无法利用缓存,每次都是完整处理。这样设计是因为池化 Processor 每次归还时都会清空缓存,开启缓存只会白白付出哈希与 map 写入开销,永远命中不了。
  • 归还时重置状态:每次调用结束归还 Processor 前,依次执行 ResetStatisticsaudit.Wait()ClearAuditLogClearCache,防止跨调用的统计、审计、缓存状态泄漏。
  • 已关闭的 Processor 不归还:若 Processor 在使用过程中被关闭(属于误用),归还逻辑会直接丢弃它而不放回池中(sync.Pool 允许缺失 Put,下次 Getpool.New 重建)。
  • panic 兜底pool.New 仅在库不变量被破坏时 panic(poolCfgDefaultConfig() 派生,按构造即合法);此 panic 经 getPooledProcessorSafe 捕获并包装为 ErrInternalPanic 返回,不会逃逸到公开 API。

配置参数解析

所有包函数的 cfg ...Config 是可选变长参数,由内部 resolveConfig 解析:

传入参数行为是否走池化
不传使用 DefaultConfig()是(pooled=true
传 1 个使用该 Configpooled=false
传 ≥2 个返回 ErrMultipleConfigs

关键差异

传入自定义 Config不走 sync.Pool——池只存储基于 DefaultConfig() 的 Processor,无法安全复用配置不同的实例。此时每次调用都会 New 一个临时 Processor,用完即 Close。若需在高频调用中复用自定义配置,请直接创建 Processor

内容提取

Extract

从 HTML 字节中提取内容,返回完整的 Result

go
func Extract(htmlBytes []byte, cfg ...Config) (*Result, error)

参数

参数类型说明
htmlBytes[]byteHTML 内容
cfg...Config可选配置,最多一个

示例

go
result, err := html.Extract(data)
if err != nil {
    log.Fatal(err)
}
fmt.Println(result.Title, result.Text)

完整可运行示例(展示字段访问与错误处理):

go
package main

import (
	"fmt"
	"log"

	"github.com/cybergodev/html"
)

func main() {
	data := []byte(`<html><head><title>示例页面</title></head>
<body><h1>欢迎</h1><p>正文内容<a href="https://example.com">链接</a>。</p></body></html>`)

	// 不传 Config,走池化路径
	result, err := html.Extract(data)
	if err != nil {
		log.Fatalf("提取失败: %v", err)
	}

	fmt.Println("标题:", result.Title)
	fmt.Println("字数:", result.WordCount)
	fmt.Println("链接数:", len(result.Links))
	// 输出:
	// 标题: 示例页面
	// 字数: 4
	// 链接数: 1
}

错误返回Extract 返回与 Processor.Extract 相同的错误,并额外可能返回:

错误条件
ErrMultipleConfigs传入 2 个及以上 Config
ErrInvalidConfig(包裹在 *ConfigError传入的 Config 校验失败(如 MaxInputSize<=0

ExtractFromFile

从 HTML 文件提取内容。

go
func ExtractFromFile(filePath string, cfg ...Config) (*Result, error)

错误返回:除 Extract 的错误外,文件访问可能返回 *FileError,包裹 ErrFileNotFoundErrInvalidFilePath 或路径遍历拒绝(见 安全防护AllowedBaseDir)。

文本提取

ExtractText

仅提取纯文本内容。

go
func ExtractText(htmlBytes []byte, cfg ...Config) (string, error)

ExtractTextFromFile

从文件提取纯文本。

go
func ExtractTextFromFile(filePath string, cfg ...Config) (string, error)

上下文版本

所有函数都支持带 context.Context 的版本,用于取消和超时控制:

函数签名
ExtractWithContext(ctx context.Context, htmlBytes []byte, cfg ...Config) (*Result, error)
ExtractFromFileWithContext(ctx context.Context, filePath string, cfg ...Config) (*Result, error)
ExtractTextWithContext(ctx context.Context, htmlBytes []byte, cfg ...Config) (string, error)
ExtractTextFromFileWithContext(ctx context.Context, filePath string, cfg ...Config) (string, error)
go
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

result, err := html.ExtractWithContext(ctx, data)

输出格式

函数签名说明
ExtractToMarkdown(htmlBytes []byte, cfg ...Config) (string, error)HTML → Markdown
ExtractToMarkdownFromFile(filePath string, cfg ...Config) (string, error)文件 → Markdown
ExtractToMarkdownWithContext(ctx context.Context, htmlBytes []byte, cfg ...Config) (string, error)带上下文
ExtractToMarkdownFromFileWithContext(ctx context.Context, filePath string, cfg ...Config) (string, error)文件 + 上下文
ExtractToJSON(htmlBytes []byte, cfg ...Config) ([]byte, error)HTML → JSON
ExtractToJSONFromFile(filePath string, cfg ...Config) ([]byte, error)文件 → JSON
ExtractToJSONWithContext(ctx context.Context, htmlBytes []byte, cfg ...Config) ([]byte, error)带上下文
ExtractToJSONFromFileWithContext(ctx context.Context, filePath string, cfg ...Config) ([]byte, error)文件 + 上下文

详细用法和示例详见 输出格式

链接提取

函数签名说明
ExtractAllLinks(htmlBytes []byte, cfg ...Config) ([]LinkResource, error)提取所有链接
ExtractAllLinksFromFile(filePath string, cfg ...Config) ([]LinkResource, error)从文件提取链接
ExtractAllLinksWithContext(ctx context.Context, htmlBytes []byte, cfg ...Config) ([]LinkResource, error)带上下文
ExtractAllLinksFromFileWithContext(ctx context.Context, filePath string, cfg ...Config) ([]LinkResource, error)文件 + 上下文

详细用法和示例详见 链接提取

批量处理

函数签名说明
ExtractBatch(htmlContents [][]byte, cfg ...Config) *BatchResult批量提取
ExtractBatchWithContext(ctx context.Context, htmlContents [][]byte, cfg ...Config) *BatchResult带上下文
ExtractBatchFiles(filePaths []string, cfg ...Config) *BatchResult批量文件提取
ExtractBatchFilesWithContext(ctx context.Context, filePaths []string, cfg ...Config) *BatchResult文件 + 上下文

详细用法和示例详见 批量处理

包函数 vs Processor

两者底层都调用 Processor,但在资源复用与状态保留上差异明显:

维度包函数Processor
缓存(池化配置 MaxCacheEntries=0有(命中返回深拷贝)
统计每次重置(归还时 ResetStatistics累积,可随时 GetStatistics
审计日志每次清空(归还时 ClearAuditLog累积,可 GetAuditLog 查询
自定义 Config每次创建+销毁临时 Processor复用同一实例
生命周期自动管理(池/临时实例)需手动 defer Close()
适用场景一次性调用、脚本、低频请求高频调用、长驻服务、需缓存

选择建议

单次提取或偶发调用用包函数最省心;若要在循环、HTTP handler、批处理中反复提取,创建一个长生命周期的 Processor 并复用,可借助缓存显著降低开销。