我正在使用Golang的内置html库.

package main

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

    "golang.org/x/net/html"
)

const url = "https://google.com"

func main() {
    resp, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 {
        log.Fatalf("Status code error: %d %s", resp.StatusCode, resp.Status)
    }

    h := html.NewTokenizer(resp.Body)

    for {
        if h.Next() == html.ErrorToken {
            break
        }

        l := len(h.Token().Attr)

        if l != 0 {
            fmt.Println("=======")
            fmt.Println("Length", l) // greater than 0
            fmt.Println("Attr", h.Token().Attr) // empty all the times
        }
    }
}

以下是输出结果

=======
Length 2
Attr []
typeof Attr []html.Attribute
=======
Length 8
Attr []
typeof Attr []html.Attribute
=======
Length 1
Attr []
typeof Attr []html.Attribute
=======
Length 1
Attr []
typeof Attr []html.Attribute

go版本

go版本 go1.17.7 linux/amd64

h.Token().Attr为空时,为什么Go认为h.Token().Attr的长度不是零?

P、 美国:保存h.Token().Attr的输出并将其用于len,然后打印内容,一切都很好

代码:

package main

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

    "golang.org/x/net/html"
)

const url = "https://google.com"

func main() {
    resp, err := http.Get(url)
    if err != nil {
        log.Fatal(err)
    }
    defer resp.Body.Close()

    if resp.StatusCode != 200 {
        log.Fatalf("Status code error: %d %s", resp.StatusCode, resp.Status)
    }

    h := html.NewTokenizer(resp.Body)

    for {
        if h.Next() == html.ErrorToken {
            break
        }

        attrs := h.Token().Attr // save the output here and use it everywhere else
        l := len(attrs)

        if l != 0 {
            fmt.Println("=======")
            fmt.Println("Length", l)
            fmt.Println("Attr", attrs)
        }
    }
}

输出

Length 3
Attr [{ value AJiK0e8AAAAAYtZT7PXDBRBC2BJawIxezEfmIL6Aw5Uy} { name iflsig} { type hidden}]
=======
Length 4
Attr [{ class fl sblc} { align left} { nowrap } { width 25%}]
=======
Length 1
Attr [{ href /advanced_search?hl=en-IN&authuser=0}]
=======
Length 4
Attr [{ id gbv} { name gbv} { type hidden} { value 1}]

推荐答案

Tokenizer有一种有趣的界面,在对Next()的调用之间,不允许多次调用Token().正如doctor 所说:

In EBNF notation, the valid call sequence per token is:
Next {Raw} [ Token | Text | TagName {TagAttr} ]

也就是说:拨打Next()后,您可以拨打Raw()零次或多次;然后你可以:

  • Token()打一次电话,
  • Text()打一次电话,
  • 调用TagName()一次,然后再调用TagAttr()零次或更多次(可能根本不需要,因为您不关心属性,或者有足够的时间检索所有属性).
  • 或者什么也不做(也许你跳过了 token ).

无序调用的结果是未定义的,因为这些方法修改了内部状态——它们不是纯粹的访问器.在第一个代码段中,在对Next()的调用之间调用了Token()次,因此结果无效.所有属性都由第一个调用使用,而不是由后面的调用返回.

Go相关问答推荐

如何获得与cksum相同的CRC 32?

如何在AWS SDK Go v2 STS上正确使用重试

如何修复Go中调用GetRawInputDeviceInfA Windows API函数时的错误?

GORM Find(&;Room)操作使用空数据而不是实际数据填充 struct

使用ciph.AEAD.Seal()查看内存使用情况

是不是有什么原因导致`Strings.EqualFold`不先进行长度比较?

exec的可执行决议.命令+路径

如何修复 Go 中协议缓冲区定义中重新定义的字段?

如何为循环扫描的bufio scanner 设置超时?

Go 中如何判断 struct 体是否包含另一个 struct 体?

Golang Docker Selenium Chrome

使用GOTK3和librsvg在Go中如何加载内联SVG?

Go Programming Language书上的例子server2错了吗?

你如何在 Golang 代码中测试 filepath.Abs​​ 失败?

如何匹配两次出现的相同但随机字符串之间的字符

如何将具有嵌入式 struct 的 struct 展平为 json

Golang:隐式 struct 匹配

如何将类型转换为字节数组golang

为什么 Go 不允许将一个泛型分配给另一个泛型?

更改单个像素的 colored颜色 - Golang 图像