devlog

【Go】net/html で要素を特定する

2023-06-19

こんにちは。Goの話です。
net/htmlでHTMLをパースするとき要素の特定に四苦八苦しました

net/htmlでHTMLをパースする

HTMLのパースには golang.org/x/net/html を使います。例えば次のように使います。

import ( "fmt" "strings" "golang.org/x/net/html" ) func main() { // io.Reader へ r := strings.NewReader(`<html><head></head><body></body></html>`) node, _ := html.Parse(r) fmt.Printf("%v\n", node.Type == html.DocumentNode) // true fmt.Printf("%v\n", node.FirstChild.Data) // html }

html.Parse すると Node が返ります。

要素を取得する

シンプルなHTMLです。各要素を取得してみます

r := strings.NewReader(` <html><head></head><body><a href="/" class="text-lg w-24">cc</a></body></html> `) node, _ := html.Parse(r) fmt.Printf("%v\n", node.FirstChild.Data) // html fmt.Printf("%v\n", node.FirstChild.FirstChild.Data) // head bodyElm := node.FirstChild.FirstChild.NextSibling // head の次の要素を取得 fmt.Printf("%v\n", bodyElm.Data) // body

 
ポイントは FirstChild と NextSibling です

  • FirstChild で、一番初めの子要素を取得できます
  • NextSibling で、次の要素(兄弟)を取得できます

属性を取得する

classhref を取得します

r := strings.NewReader(` <html><head></head><body><a href="/" class="text-lg w-24">cc</a></body></html> `) node, _ := html.Parse(r) bodyElm := node.FirstChild.FirstChild.NextSibling // head の次の要素を取得 aElm := bodyElm.FirstChild fmt.Printf("%v\n", aElm.Data) // a fmt.Printf("%v\n", aElm.Attr[0].Key) // href fmt.Printf("%v\n", aElm.Attr[0].Val) // / fmt.Printf("%v\n", aElm.Attr[1].Key) // class fmt.Printf("%v\n", aElm.Attr[1].Val) // text-lg w-24

属性は Attr で取得できます。
ちなみにdata属性も同じように取得できました。

終わりに

FirstChild や NextSibling は DOM の Node にインタフェースが似ているようです。

HTMLが複雑なときは goquery など、よりレイヤーの高いAPIと組み合わせて使ったほうがいいかもしれません。

  • 作成日
    2023-06-19
  • 更新日
    2023-07-10