Golang网络爬虫,忽略表格中的特定单元格。

huangapple go评论79阅读模式
英文:

golang web scraper, ignoring specific cells of a table

问题

我正在开发一个小型网络爬虫,只是为了熟悉Go语言。目前,它可以从维基百科的一个表格中获取信息,然后从单元格中获取特定的信息。我目前没有代码(不在家),但它看起来与下面的代码非常相似:

func main() {
    doc, err := goquery.NewDocument("http://monsterhunter.wikia.com/wiki/MH4:_Item_List")
    if err != nil {
        log.Fatal(err)
    }

    doc.Find("tbody").Each(func(i int, s *goquery.Selection) {
        title := s.Find("td").Text()
        fmt.Printf(title)
    })
}

问题是,在这个网站上,第一个单元格是一个图片,所以它会打印出图片的源代码,而我不想要这个。如何忽略大表格中每一行的第一个单元格?

英文:

I'm working on a small web scraper to just get a feel of golang. It currently is grabbing info off of a wiki from a table and then grabbing info specifically from cells. I don't currently have the code on me (not currently at home) but it looks fairly similar to this:

    func main() {
        doc, err := goquery.NewDocument("http://monsterhunter.wikia.com/wiki/MH4:_Item_List")
        if err != nil {
                log.Fatal(err)
        }

        doc.Find("tbody").Each(func(i int, s *goquery.Selection) {
                title := s.Find("td").Text()
                fmt.Printf(title)
        })
}

The issue is that on this website the first cell is an image, so it prints the image source which I don't want. How can I ignore the first cell in each row of the large table?

答案1

得分: 4

让我们澄清一些事情。Selection 是一组符合某些条件的节点集合。

doc.Find()Selection.Find(),它返回一个包含符合条件的元素的新 SelectionSelection.Each() 遍历集合中的每个元素,并调用传递给它的函数值。

所以在你的情况下,Find("tbody") 将找到所有的 tbody 元素,Each() 将遍历所有的 tbody 元素,并调用你的匿名函数。

在你的匿名函数中,s 是一个 tbody 元素的 Selection。你调用 s.Find("td"),它将返回一个新的 Selection,其中包含当前表格的所有 td 元素。所以当你在这上面调用 Text() 时,它将是每个 td 元素及其后代的组合文本内容。这不是你想要的。

你应该在 s.Find("td") 返回的 Selection 上再调用另一个 Each()。并检查传递给第二个匿名函数的 Selection 是否有一个 img 子元素。

示例代码:

doc.Find("tbody").Each(func(i int, s *goquery.Selection) {
    // 这里的 s 是一个 tbody 元素
    s.Find("td").Each(func(j int, s2 *goquery.Selection) {
        // 这里的 s2 是一个 td 元素
        if s3 := s2.Find("img"); s3 != nil && s3.Length() > 0 {
            return // 这个 TD 至少有一个 img 子元素,跳过它
        }
        fmt.Printf(s2.Text())
    })
})

或者你可以搜索 tr 元素,并通过检查传递给第三个匿名函数的索引是否为 0(第一个子元素)来跳过每行的第一个 td 子元素,类似于这样:

doc.Find("tbody").Each(func(i int, s *goquery.Selection) {
    // 这里的 s 是一个 tbody 元素
    s.Find("tr").Each(func(j int, s2 *goquery.Selection) {
        // 这里的 s2 是一个 tr 元素
        s2.Find("td").Each(func(k int, s3 *goquery.Selection) {
            // 这里的 s3 是一个 td 元素
            if k == 0 {
                return // 这是行中的第一个 TD
            }
            fmt.Printf(s3.Text())
        })
    })
})
英文:

Let's clear some things. A Selection is a collection of nodes matching some criteria.

doc.Find() is Selection.Find() which returns a new Selection containing the elements matching the criteria. And Selection.Each() iterations over each of the elements of the collection and calls the function value passed to it.

So in your case Find("tbody") will find all tbody elements, Each() will iterate over all tbody elements and call your anonymous function.

Inside your anonymous function s is a Selection of one tbody element. You call s.Find("td") which will return a new Selection which will contain all the td elements of the current table. So when you call Text() on this, it will be the combined text contents of each td elements including their descendants. This is not what you want.

What you should do is call another Each() on the Selection returned by s.Find("td"). And check if the Selection passed to the 2nd anonymous function has an img child.

Example code:

doc.Find("tbody").Each(func(i int, s *goquery.Selection) {
    // s here is a tbody element
    s.Find("td").Each(func(j int, s2 *goquery.Selection) {
        // s2 here is a td element
        if s3 := s2.Find("img"); s3 != nil && s3.Length() > 0 {
            return // This TD has at least one img child, skip it
        }
        fmt.Printf(s2.Text())
    })
})

Alternatively you could search tr elements and skip the first td child of each row by checking if the index passed to the 3rd anonymous function is 0 (first child), something like this:

doc.Find("tbody").Each(func(i int, s *goquery.Selection) {
    // s here is a tbody element
    s.Find("tr").Each(func(j int, s2 *goquery.Selection) {
        // s2 here is a tr element
        s2.Find("td").Each(func(k int, s3 *goquery.Selection) {
            // s3 here is a td element
            if k == 0 {
                return // This is the first TD in the row
            }
            fmt.Printf(s3.Text())
        })
    })
})

huangapple
  • 本文由 发表于 2015年6月1日 15:53:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/30568318.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定