【Go语言爬虫系列02】HTML解析与Goquery技术详解

📚 原创系列: “Go语言爬虫系列”

🔄 转载说明: 本文最初发布于"Gopher部落"微信公众号,经原作者授权转载。

🔗 关注原创: 欢迎扫描文末二维码,关注"Gopher部落"微信公众号获取第一手Go技术文章。

📑 Go语言爬虫系列导航

本文是【Go语言爬虫系列】的第2篇,点击下方链接查看更多文章

🚀 Go爬虫系列:共12篇
  1. 爬虫入门与Colly框架基础
  2. HTML解析与Goquery技术详解👈 当前位置
  3. Colly高级特性与并发控制
  4. 爬虫架构设计与实现(即将发布)
  5. 反爬虫策略应对技术(即将发布)
  6. 模拟登录与会话维持(即将发布)
  7. 动态网页爬取技术(即将发布)
  8. 分布式爬虫设计与实现(即将发布)
  9. 数据存储与处理(即将发布)
  10. 爬虫性能优化技术(即将发布)
  11. 爬虫安全与合规性(即将发布)
  12. 综合项目实战:新闻聚合系统(即将发布)

📖 文章导读

上一篇文章中,我们学习了爬虫的基本概念和Colly框架的基础用法。本文作为系列的第二篇,将深入HTML解析领域,重点介绍:

  1. HTML文档结构与DOM树的基本概念
  2. Goquery库的安装与核心功能
  3. CSS选择器语法与高级用法
  4. DOM元素遍历与精准选择技术
  5. 结构化数据提取与表格处理实战

掌握这些技术后,您将能够从任何HTML页面中精确提取所需的数据,无论它的结构多么复杂。

一、HTML文档结构与DOM基础

1.1 理解HTML与DOM

在深入学习HTML解析技术前,我们需要先理解HTML文档的结构和DOM(文档对象模型)的概念:

**HTML(超文本标记语言)**是网页的标准结构化语言,由一系列元素(elements)组成,这些元素通过标签(tags)来定义。例如:

<!DOCTYPE html>
<html>
<head>
  <title>页面标题</title>
</head>
<body>
  <div id="main">
    <h1 class="title">标题文本</h1>
    <p>段落内容</p>
    <ul>
      <li>列表项1</li>
      <li>列表项2</li>
    </ul>
  </div>
</body>
</html>

**DOM(Document Object Model,文档对象模型)**是HTML文档的编程接口,它将HTML文档表示为树状结构,其中每个节点都是文档的一部分(如元素、属性或文本)。这种树状结构使我们能够通过编程方式访问和操作HTML元素。

DOM树结构示例:

上面的HTML代码在DOM中的表示形式是一棵树,html元素是根节点,head和body是其子节点,依此类推。每个元素可以有属性(如id、class)、内容和子元素。

1.2 HTML解析的挑战

在爬虫开发中,HTML解析面临以下常见挑战:

  1. 结构多变性:不同网站的HTML结构差异很大,甚至同一网站的不同页面也可能有不同结构
  2. 非标准HTML:实际网页中常见格式错误或不规范的HTML代码
  3. 动态内容:通过JavaScript生成的内容在源代码中不可见
  4. 大量冗余信息:网页中包含大量与目标数据无关的内容
  5. 结构变化:网站更新可能导致HTML结构改变,使原有解析逻辑失效

为了应对这些挑战,我们需要强大而灵活的HTML解析工具。在Go语言中,Goquery库提供了理想的解决方案。

二、Goquery库入门

2.1 Goquery简介

Goquery是Go语言中最流行的HTML解析库,由Martin Angers创建,深受jQuery启发。它提供了类似jQuery的语法和API,使HTML元素选择和操作变得简单直观。

Goquery的主要特点:

  • 熟悉的语法:对熟悉jQuery的开发者友好
  • 强大的选择器:支持几乎所有CSS选择器
  • 链式操作:支持函数链式调用
  • DOM遍历:提供丰富的DOM导航方法
  • 高性能:基于高效的net/html标准库

2.2 安装Goquery

使用Go Modules安装Goquery:

# 初始化模块(如果尚未初始化)
go mod init myproject

# 安装Goquery
go get github.com/PuerkitoBio/goquery

2.3 基本用法示例

下面是一个简单的Goquery使用示例:

package main

import (
	"fmt"
	"log"
	"net/http"
	"strings"

	"github.com/PuerkitoBio/goquery"
)

func main() {
   
   
	// 发起HTTP请求获取网页内容
	res, err := http.Get("https://news.example.com")
	if err != nil {
   
   
		log.Fatal(err)
	}
	defer res.Body.Close()
	if res.StatusCode != 200 {
   
   
		log.Fatalf("状态码错误: %d %s", res.StatusCode, res.Status)
	}

	// 加载HTML文档
	doc, err := goquery.NewDocumentFromReader(res.Body)
	if err != nil {
   
   
		log.Fatal(err)
	}

	// 使用CSS选择器查找元素
	doc.Find("article .title").Each(func(i int, s *goquery.Selection) {
   
   
		// 获取文本内容
		title := s.Text()
		// 去除多余空白
		title = strings.TrimSpace(title)
		fmt.Printf("文章标题 %d: %s\n", i+1, title)

		// 获取链接地址
		href, exists := s.Parent().Attr("href")
		if exists {
   
   
			fmt.Printf("链接地址: %s\n", href)
		}
	})
}

这个例子展示了Goquery的基本工作流程:

  1. 获取HTML内容
  2. 创建Goquery文档对象
  3. 使用选择器查找元素
  4. 处理选中的元素(获取文本、属性等)

2.4 与Colly框架集成

如果您正在使用Colly框架(如上一篇文章所介绍的),可以很容易地集成Goquery:

c := colly.NewCollector()

c.OnHTML("article", func(e *colly.HTMLElement) {
   
   
	// e.DOM是一个goquery.Selection对象
	e.DOM.Find(".title").Each(func(i int, s *goquery.Selection) {
   
   
		title := s.Text()
		fmt.Printf("文章标题: %s\n", title)
	})
})

c.Visit("https://example.com")

在Colly中,HTMLElement结构体包含一个DOM字段,它是一个goquery.Selection对象,提供了对当前元素的所有Goquery功能的访问。

三、CSS选择器详解

3.1 基本选择器

CSS选择器是从HTML文档中选择元素的模式。Goquery支持大多数CSS3选择器。以下是最常用的基本选择器:

选择器 示例 描述
元素选择器 p 选择所有<p>元素
ID选择器 #main 选择id为"main"的元素
类选择器 .title 选择所有class包含"title"的元素
组合选择器 div, p 选择所有<div>元素和所有<p>元素
后代选择器 div p 选择<div>内的所有<p>元素
子元素选择器 div > p 选择<div>的直接子元素<p>
相邻兄弟选择器 h1 + p 选择紧跟在<h1>后的<p>元素
一般兄弟选择器 h1 ~ p 选择<h1>后的所有同级<p>元素

3.2 属性选择器

属性选择器允许根据元素的属性来选择元素:

选择器 示例 描述
[attr] [href] 选择有href属性的元素
[attr=value] [type="text"] 选择type="text"的元素
[attr^=value] [href^="https"] 选择href以"https"开头的元素
[attr$=value] [href$=".pdf"] 选择href以".pdf"结尾的元素
[attr*=value] [href*="example"] 选择href包含"example"的元素

3.3 伪类选择器

Goquery支持部分CSS3伪类选择器:

选择器 示例 描述
:first-child li:first-child 选择作为第一个子元素的每个<li>元素
:last-child li:last-child 选择作为最后一个子元素的每个<li>元素
:nth-child(n) tr:nth-child(2n) 选择作为第2n个子元素的每个<tr>元素(偶数行)
:empty div:empty 选择没有子元素的<div>元素
:not(selector) div:not(.ignore) 选择不包含class="ignore"的所有<div>元素

3.4 选择器组合与优先级

复杂的选择需求通常需要组合多种选择器:

// 选择具有特定class的div中的第一个段落
doc.Find("div.content > p:first-child")
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gopher部落

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值