商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > Golang解析HTML方法详解

Golang解析HTML方法详解

  发布于2026-03-09 阅读(0)

扫一扫,手机访问

必须先调用 html.Parse() 或 html.ParseFragment() 构建 DOM 树,不可直接操作 html.Node;Parse 用于完整 HTML 文档,需 io.Reader 输入;ParseFragment 适用于 HTML 片段。

如何在Golang中解析HTML页面_Golang net/html HTML解析方法

net/html 解析 HTML 时,必须先调用 html.Parse() 获取根节点

直接对原始 HTML 字符串调用 html.Node 相关操作会 panic,因为没有解析器上下文。必须先通过 html.Parse()html.ParseFragment() 构建 DOM 树。

  • html.Parse() 用于完整 HTML 文档(含 <html><head> 等),输入需是 io.Reader,常见用法:
    doc, err := html.Parse(strings.NewReader(htmlStr))
    if err != nil {
        log.Fatal(err)
    }
  • html.ParseFragment() 适合解析片段(如仅 <div>...),需传入一个“上下文节点”(如 &html.Node{Type: html.ElementNode, Data: "body"}),否则可能丢节点或 panic
  • 注意:解析器不校验编码,默认按 UTF-8 处理;若 HTML 声明为 gbkutf-8 但实际字节非 UTF-8,会读出乱码甚至提前截断

遍历节点时,node.Typenode.Data 更可靠

很多新手误以为查 node.Data == "div" 就能定位元素,但 Data 在不同 Type 下含义不同:文本节点存内容,注释节点存注释文字,元素节点才存标签名。漏判 Type 会导致逻辑错位或空指针。

  • 关键类型常量:html.ElementNode(标签)、html.TextNode(文本)、html.CommentNode(注释)、html.DoctypeNode(doctype)
  • 安全遍历示例:
    func findDivs(n *html.Node) {
        if n.Type == html.ElementNode && n.Data == "div" {
            // 处理 div 元素
            fmt.Println("found div")
        }
        for c := n.FirstChild; c != nil; c = c.NextSibling {
            findDivs(c)
        }
    }
  • 不要依赖 n.DataAtom —— 它是内部优化字段,未导出且仅在特定构建下有效,跨平台或新版 Go 可能失效

node.Attr 是切片,查属性必须遍历,没有 GetAttribute() 这种方法

Go 的 net/html 不提供类似 jQuery 的 attr("href") 便捷接口,所有属性访问都得手动循环 node.Attr 切片比对 Key

  • 常见错误:写成 node.Attr["href"] —— 编译失败,因为 Attr[]html.Attribute 类型,不是 map
  • 正确写法:
    func getHref(n *html.Node) (href string) {
        for _, a := range n.Attr {
            if a.Key == "href" {
                href = a.Val
                break
            }
        }
        return href
    }
  • 注意大小写:HTML 属性名不区分大小写,但 net/html 不做归一化,"HREF""href" 被视为不同 key;生产环境建议统一转小写再比较

解析后不调用 html.Render() 就无法还原 HTML 字符串

如果你从网页提取结构后想拼回 HTML 片段(比如清洗后重新生成),不能靠字符串拼接,必须用 html.Render() 写入 io.Writer。否则丢失转义、闭合逻辑、自闭合标签处理(如 <img>)等细节。

  • html.Render() 会自动处理特殊字符转义(如 <&lt;)、标签闭合、空白压缩策略(取决于节点类型)
  • 简单还原示例:
    var buf bytes.Buffer
    err := html.Render(&buf, doc)
    if err != nil {
        log.Fatal(err)
    }
    htmlOut := buf.String() // 此时才是合法可渲染的 HTML
  • 注意:若只取部分子树(如某个 <div>),要确保其作为独立片段可渲染 —— 比如 <table> 子节点单独 render 可能缺 <tbody>,浏览器容错强,但服务端处理时需留意
解析 HTML 最容易被忽略的是编码推断和错误恢复机制:net/html 在遇到非法嵌套(如 <p><div></p></div>)时会自动修复 DOM 结构,这和浏览器一致,但也意味着你写的 XPath 或层级假设可能在意外情况下失效。
本文转载于:互联网 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。
  • using namespace 使用中遇到的问题怎么解决 正版软件
    using namespace 使用中遇到的问题怎么解决
    命名空间的基本概念与常见引入问题在C++等编程语言中,命名空间(namespace)是一种将代码标识符(如变量、函数、类名)封装在特定名称下的机制,其主要目的是避免命名冲突,尤其是在大型项目或使用多个第三方库时。使用“using namespace”指令可以将指定命名空间中的所有名称引入当前作用域,
    10天前 0
  • c语言函数递归 实操经验总结:这些技巧很实用 正版软件
    c语言函数递归 实操经验总结:这些技巧很实用
    理解递归的基本原理在C语言中,递归是一种函数调用自身的编程技术。要掌握它,首先需要理解其核心思想:将一个复杂的大问题,分解为一个或几个与原问题相似但规模更小的子问题,直到子问题足够简单,可以直接求解。这个过程通常包含两个关键部分:递归出口和递归体。递归出口定义了问题何时不再继续分解,即最简单、可直接
    10天前 0
  • c语言函数递归 怎么选?常见方案对比分析 正版软件
    c语言函数递归 怎么选?常见方案对比分析
    递归函数的基本概念与适用场景在C语言编程中,递归是一种函数调用自身的编程技巧。它并非适用于所有问题,但在处理某些具有自相似结构的问题时,能提供极其清晰和优雅的解决方案。递归的核心思想是将一个大规模问题分解为一个或多个同类型但规模更小的子问题,直到子问题简单到可以直接求解。典型的适用场景包括树形结构的
    10天前 0
  • Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解 正版软件
    Objective-C 内存管理入门:从 alloc 到 dealloc 的生命周期详解
    理解内存管理的基石在Objective-C的编程世界中,内存管理是开发者必须掌握的核心技能之一。它直接关系到应用的性能、稳定性与资源利用效率。与一些采用自动垃圾回收机制的语言不同,Objective-C在很长一段时间里,依赖一套基于引用计数的、需要开发者部分介入的管理规则。这套规则的核心思想是明确的
    10天前 0
  • 如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏 正版软件
    如何正确使用 dealloc 以避免 iOS 应用中的内存泄漏
    理解 dealloc 的角色与时机在 iOS 应用开发中,内存管理是保障应用性能与稳定性的基石。dealloc 方法是 Objective-C 中对象生命周期结束时的关键回调,它标志着对象即将被系统回收内存。正确理解其触发时机至关重要:当一个对象的引用计数降为零时,运行时系统会自动调用该对象的 de
    10天前 0