编程

goquery:HTML 解析器

448 2023-10-10 16:17:00

简介

什么是 goquery?

goquery 是由 Go 实现的基于 Go 的 net/html 包和 CSS 选择器库 cascadia 的 HTML 解析库。

由于 net/html 解析器需要 UTF-8 编码,goquery 也同样需要,所以需要确保提供的 html 是 UTF-8 编码。

为什么用 goquery?

由于 net/html 解析器返回的是节点,而不是功能齐全的 DOM 树,所以在使用的过程中 goquery 可以提供更便利的操作。

快速上手 

我们先对微博热搜进行一个简单的解析,打印当日的热搜排名标题以及热度。

package main
import (
  "fmt"
  "github.com/PuerkitoBio/goquery"
  "log"
  "net/http"
)
type Data struct {
  number string
  title  string
  heat   string
}
func main() {
  // 爬取微博热搜网页
  res, err := http.Get("https://s.weibo.com/top/summary")
  if err != nil {
    log.Fatal(err)
  }
  defer res.Body.Close()
  if res.StatusCode != 200 {
    log.Fatalf("status code error: %d %s", res.StatusCode, res.Status)
  }
  //将html生成goquery的Document
  dom, err := goquery.NewDocumentFromReader(res.Body)
  if err != nil {
    log.Fatalln(err)
  }
  var data []Data
  // 筛选class为td-01的元素
  dom.Find(".td-01").Each(func(i int, selection *goquery.Selection) {
    data = append(data, Data{number: selection.Text()})
  })
  // 筛选class为td-02的元素下的a元素
  dom.Find(".td-02>a").Each(func(i int, selection *goquery.Selection) {
    data[i].title = selection.Text()
  })
  // 筛选class为td-02的元素下的span元素
  dom.Find(".td-02>span").Each(func(i int, selection *goquery.Selection) {
    data[i].heat = selection.Text()
  })
  fmt.Println(data)
}

过滤器示例 

基于 HTML Element 元素的选择器
使用 Element 名称作为选择器,如 dom.Find("div")

dom.Find("div").Each(func (i int, selection *goquery.Selection) {
  fmt.Println(selection.Text())
})

ID 选择器
以 # 加 id 值作为选择器

dom.Find("#id").Each(func (i int, selection *goquery.Selection) {
  fmt.Println(selection.Text())
})

Class 选择器
以 . 加 class 值为选择器

dom.Find(".class").Each(func (i int, selection *goquery.Selection) {
  fmt.Println(selection.Text())
})

上面的示例可以看出,goquery 的选择器与 jQuery 的选择器用法无异,在这里就不继续赘述了,同学们可以自行探索。

常用节点属性值 

Html() 获取该节点的 html

dom.Find("table").Each(func (i int, selection *goquery.Selection) {
  fmt.Println(selection.Html())
})

Text() 获取该节点的文本值

dom.Find(".td-02>a").Each(func (i int, selection *goquery.Selection) {
  fmt.Println(selection.Text())
})

Attr() 返回节点的属性值以及该属性是否存在的布尔值

dom.Find("#execution").Each(func (i int, selection *goquery.Selection) {
  value[i], ok = selection.Attr("value")
})

Length() 返回该 Selection 的元素个数

dom.Find("td").Length()