首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用go-colly和function解析HTML返回一个空的切片。

使用go-colly和function解析HTML返回一个空的切片。
EN

Stack Overflow用户
提问于 2022-05-03 09:54:52
回答 1查看 358关注 0票数 1

我正在用colly框架解析一个网站,结果出现了一些问题。我有一个非常基本的函数getweeks()来获取和返回一些东西,但是我却得到了一个空的片段。

代码语言:javascript
复制
func getWeeks(c *colly.Collector) []string {
    var wks []string
    c.OnHTML("div.ltbluediv", func(div *colly.HTMLElement) {
        weekName := div.DOM.Find("span").Text()  // a string Week 1, Week 2 etc 
        wks = append(wks, weekName)  // weekName has actual value is not empty
        // If `wks` printed here it shows correctly how the slice gets populated on each iteration
    })
    return wks  // returns []
}

func main() {
    c := colly.NewCollector(
    )

    w := getWeeks(c)
    fmt.Println(w)  // []

    c.OnRequest(func(r *colly.Request) {
        r.Headers.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64)")
    })

    c.Visit("target url")

}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-03 13:53:28

tl;dr:片头在OnHTML回调中被更新,但是您在main中打印的值是旧的片头。您应该转而使用*[]string

首先,传递给c.OnHTML的回调实际上只有在调用c.Visit之后才能运行,因此在getWeeks之后直接打印w,在任何情况下都会显示一个空的片段。

然而,即使在c.Visit之后打印,它也将是一个空片,为什么?

Go中的片作为一个数据结构实现--称为片头(更多信息:12)。

当您分配getWeeks的返回值时,实际上是在复制切片头,包括它的字段DataLenCap。您可以在这个操场中看到它,方法是使用%p谓词打印切片的地址(使用其他结构而不是go-colly使示例自包含):

代码语言:javascript
复制
func getWeeks(c *Foo) []string {
    var wks []string
    c.OnHTML("div.ltbluediv", func(text string) {
        weekName := text
        wks = append(wks, weekName)
    })
    fmt.Printf("%p\n", &wks)
    return wks
}

func main() {
    c := &Foo{}

    w := getWeeks(c)

    c.Visit("target url")
    fmt.Printf("%p\n", &w)

}

打印两个不同的内存地址:

代码语言:javascript
复制
0xc0000ac030
0xc0000ac018

现在,如果您继续在堆栈溢出中查找关于片和append行为的信息,您可能会发现,如果该片具有足够的容量(123.),则支持数组不会重新分配。

但是,即使通过以足够的容量初始化wks来确保支持数组是相同的,w的值仍然是原始片头的副本,因此具有0长度的。这在这个操场中得到了演示,它打印:

代码语言:javascript
复制
in getWeeks reflect.SliceHeader{Data:0xc0000121b0, Len:0, Cap:3}
in callback reflect.SliceHeader{Data:0xc0000121b0, Len:1, Cap:3}
in callback reflect.SliceHeader{Data:0xc0000121b0, Len:2, Cap:3}
in callback reflect.SliceHeader{Data:0xc0000121b0, Len:3, Cap:3}
[]
in main reflect.SliceHeader{Data:0xc0000121b0, Len:0, Cap:3}

您可以通过重新注册w (游乐场)来调整它的长度:

代码语言:javascript
复制
c.Visit("target url")
w = w[0:3]
fmt.Println(w) // [foo bar baz]

但这意味着你需要事先知道一个不引起重新分配的合理容量,以及重新分配的最终长度。

相反,返回一个指向片的指针:

代码语言:javascript
复制
func getWeeks(c *colly.Collector) *[]string {
    wks := &[]string{}
    c.OnHTML("div.ltbluediv", func(div *colly.HTMLElement) {
        weekName := div.DOM.Find("span").Text()
        *wks = append(*wks, weekName) 
    })
    return wks
}

或者将指针传递到getWeeks

代码语言:javascript
复制
func getWeeks(c *colly.Collector, wks *[]string) {
    c.OnHTML("div.ltbluediv", func(div *colly.HTMLElement) {
        weekName := div.DOM.Find("span").Text()
        *wks = append(*wks, weekName)
    })
}

固定操场:https://go.dev/play/p/yhq8YYnkFsv

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72097676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档