【问题标题】:How can I match text that precedes an `<a>` tag then return the `<a>` node?如何匹配 `<a>` 标记之前的文本,然后返回 `<a>` 节点?
【发布时间】:2020-04-07 22:59:36
【问题描述】:

我有以下内容,我试图仅捕获第二种情况,其中文本匹配But I want this one here。目前,它涵盖了这两种情况。

package main

import (
    "bytes"
    "fmt"
    "io"
    "strings"

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

func getTag(doc *html.Node, tag string) []*html.Node {
    var nodes []*html.Node
    var crawler func(*html.Node)
    crawler = func(node *html.Node) {
        if node.Type == html.ElementNode && node.Data == tag {
            nodes = append(nodes, node)
            return
        }
        for child := node.FirstChild; child != nil; child = child.NextSibling {
            crawler(child)
        }
    }
    crawler(doc)
    return nodes
}

func main() {
    doc, _ := html.Parse(strings.NewReader(testHTML))
    nodes := getTag(doc, "a")

    var buf bytes.Buffer
    w := io.Writer(&buf)
    for i, node := range nodes {
        html.Render(w, node)
        if i < (len(nodes) - 1) {
            w.Write([]byte("\n"))
        }
    }

    fmt.Println(buf.String())
}

var testHTML = `<html><body>
I do not want this link here <a href="blah">link text</a>
But I want this one here <a href="blah blah">more link text</a>
</body></html>`

这个输出:

<a href="blah">link text</a> <a href="blah blah">more link text</a>

我想匹配&lt;a&gt; 标记之前的特定文本,如果匹配,则返回&lt;a&gt; 节点。例如,传入But I want this one here,它会返回&lt;a href="blah blah"&gt;more link text&lt;/a&gt;。有人告诉我不要用正则表达式解析 html,但现在我被卡住了。

【问题讨论】:

  • Regex 非常适合这个。请改用 DOM 解析器。
  • 那里的答案说不要使用正则表达式
  • 是的,完全正确。不建议尝试使用正则表达式来解决此类问题。

标签: html regex parsing go


【解决方案1】:

您实际上已经很接近了,因为您已经在使用正确的解析器(html.Parse 来自 golang.org/x/net/html)。

这里的诀窍是页面的各种元素可以方便地绑定在一起,因此如果您愿意,可以使用现有的crawler 代码和稍后的过滤功能。 (您可以改为将过滤直接组合到爬虫中。)

每个n *html.ElementNode 前面都有一些东西,除非它是块中的初始元素(文档的第一个元素或第一个子节点),并且 somethingn.PrevSibling 中。如果它的类型是html.TextNode,那么你有一个如下形式的序列:

some text<a ...>thing</a>

您可以检查上一个节点中的“一些文本”:

func wanted(re *regexp.Regexp, n *html.Node) bool {
    if n.PrevSibling == nil || n.PrevSibling.Type != html.TextNode {
        return false
    }
    return re.MatchString(n.PrevSibling.Data)
}

这并不完美,因为你可以拥有,例如:

text <font></font> broken <font></font>up<a href="lastlink">last link</a>

并且代码将尝试匹配字符串up,此时您可能应该将文本一起放入text broken up 并将其传递给匹配器。查看更多完整示例here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-13
    • 2010-10-10
    • 2019-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多