goquery- 从一个 html 标签中提取文本并将其添加到下一个标签
goquery- Extract text from one html tag and add it to the next tag
是的,很抱歉标题没有解释任何内容。我需要举个例子。
这是我发布的另一个 的延续,它解决了一个问题,但不是所有问题。我已将该问题的大部分背景信息放入这个问题中。此外,我只研究了大约 5 天的 Go(我几个月前才开始学习代码),所以我 90% 确定我已经接近弄清楚我想要什么,问题是我有一些愚蠢的语法错误。
情况
我正在尝试使用 goquery
来解析网页。 (最终我想把一些数据放在数据库中)。这是它的样子:
<html>
<body>
<h1>
<span class="text">Go </span>
</h1>
<p>
<span class="text">totally </span>
<span class="post">kicks </span>
</p>
<p>
<span class="text">hacks </span>
<span class="post">its </span>
</p>
<h1>
<span class="text">debugger </span>
</h1>
<p>
<span class="text">should </span>
<span class="post">be </span>
</p>
<p>
<span class="text">called </span>
<span class="post">ogle </span>
</p>
<h3>
<span class="statement">true</span>
</h3>
</body>
<html>
Objective
我愿意:
- 提取
<h1..."text"
的内容。
- 将提取的内容插入(并连接)到
<p..."text"
的内容中。
- 仅对 紧跟
<h1>
标签的 <p>
标签执行此操作。
- 对页面上
<h1>
标签中的 所有 执行此操作。
再一次,一个例子可以更好地解释 ^this。这就是我想要的样子:
<html>
<body>
<p>
<span class="text">Go totally </span>
<span class="post">kicks </span>
</p>
<p>
<span class="text">hacks </span>
<span class="post">its </span>
</p>
<p>
<span class="text">debugger should </span>
<span class="post">be </span>
</p>
<p>
<span class="text">called </span>
<span class="post">ogle</span>
</p>
<h3>
<span class="statement">true</span>
</h3>
</body>
<html>
解决方案尝试
因为进一步区分 <h1>
标签和 <p>
标签会提供更多的解析选项,所以我想出了如何更改 <h1>
的 class
属性] 标签:
<html>
<body>
<h1>
<span class="title">Go </span>
</h1>
<p>
<span class="text">totally </span>
<span class="post">kicks </span>
</p>
<p>
<span class="text">hacks </span>
<span class="post">its </span>
</p>
<h1>
<span class="title">debugger </span>
</h1>
<p>
<span class="text">should </span>
<span class="post">be </span>
</p>
<p>
<span class="text">called </span>
<span class="post">ogle </span>
</p>
<h3>
<span class="statement">true</span>
</h3>
</body>
<html>
使用此代码:
html_code := strings.NewReader(`
code_example_above
`)
doc, _ := goquery.NewDocumentFromReader(html_code)
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
s.SetAttr("class", "title")
class, _ := s.Attr("class")
if class == "title" {
fmt.Println(class, s.Text())
}
})
我知道我可以 select <p..."text"
在 <h1..."title"
之后 doc.Find("h1+p")
或 s.Next()
在 doc.Find("h1").Each
函数内:
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
s.SetAttr("class", "title")
class, _ := s.Attr("class")
if class == "title" {
fmt.Println(class, s.Text())
fmt.Println(s.Next().Text())
}
})
我不知道如何插入从 <h1..."title"
到 <p..."text"
的文本。我已经尝试使用 s.After()
、s.Before()
和 s.Append()
的多种变体,例如:
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
s.SetAttr("class", "title")
class, _ := s.Attr("class")
if class == "title" {
s.After(s.Text())
fmt.Println(s.Next().Text())
}
})
但我不知道如何做我想做的事。
如果我改用 s.After(s.Next().Text())
,我会得到这个错误输出:
panic: expected identifier, found 5 instead
goroutine 1 [running]:
code.google.com/p/cascadia.MustCompile(0xc2082f09a0, 0x62, 0x62)
/home/*/go/src/code.google.com/p/cascadia/selector.go:59 +0x77
github.com/PuerkitoBio/goquery.(*Selection).After(0xc2082ea630, 0xc2082f09a0, 0x62, 0x5)
/home/*/go/src/github.com/PuerkitoBio/goquery/manipulation.go:18 +0x32
main.func·001(0x0, 0xc2082ea630)
/home/*/go/test2.go:78 +0x106
github.com/PuerkitoBio/goquery.(*Selection).Each(0xc2082ea600, 0x7cb678, 0x2)
/home/*/go/src/github.com/PuerkitoBio/goquery/iteration.go:7 +0x173
main.ExampleScrape()
/home/*/go/test2.go:82 +0x213
main.main()
/home/*/go/test2.go:175 +0x1b
goroutine 9 [runnable]:
net/http.(*persistConn).readLoop(0xc208047ef0)
/usr/lib/go/src/net/http/transport.go:928 +0x9ce
created by net/http.(*Transport).dialConn
/usr/lib/go/src/net/http/transport.go:660 +0xc9f
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
/usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 10 [select]:
net/http.(*persistConn).writeLoop(0xc208047ef0)
/usr/lib/go/src/net/http/transport.go:945 +0x41d
created by net/http.(*Transport).dialConn
/usr/lib/go/src/net/http/transport.go:661 +0xcbc
exit status 2
(我的脚本的行与上面示例的行不匹配,但是我的脚本的 "line 72" 包含代码 s.After(s.Next().Text())
。我不知道具体是什么 panic: expected identifier, found 5 instead
表示。)
总结
总而言之,我的问题是我不太清楚如何使用 goquery
向标签添加文本。
我想我很接近。有地鼠绝地武士能够并愿意帮助这个学徒吗?
类似这段代码的工作,它找到所有 <h1>
个节点,然后找到这些 <h1>
个节点内的所有 <span>
个节点,寻找 class text
。然后它获取 <h1>
节点的下一个元素,如果它是一个 <p>
,里面有一个 <span>
,那么它将最后一个 <span>
替换为一个新的 <span>
与新文本并删除 <h1>
.
我想知道是否可以使用 goquery
创建节点而无需编写 html...
package main
import (
"fmt"
"strings"
"github.com/PuerkitoBio/goquery"
)
var htmlCode string = `<html>
...
<html>`
func main() {
doc, _ := goquery.NewDocumentFromReader(strings.NewReader((htmlCode)))
doc.Find("h1").Each(func(i int, h1 *goquery.Selection) {
h1.Find("span").Each(func(j int, s *goquery.Selection) {
if s.HasClass("text") {
if p := h1.Next(); p != nil {
if ps := p.Children().First(); ps != nil && ps.HasClass("text") {
ps.ReplaceWithHtml(
fmt.Sprintf("<span class=\"text\">%s%s</span>)", s.Text(), ps.Text()))
h1.Remove()
}
}
}
})
})
htmlResult, _ := doc.Html()
fmt.Println(htmlResult)
}
是的,很抱歉标题没有解释任何内容。我需要举个例子。
这是我发布的另一个
情况
我正在尝试使用 goquery
来解析网页。 (最终我想把一些数据放在数据库中)。这是它的样子:
<html>
<body>
<h1>
<span class="text">Go </span>
</h1>
<p>
<span class="text">totally </span>
<span class="post">kicks </span>
</p>
<p>
<span class="text">hacks </span>
<span class="post">its </span>
</p>
<h1>
<span class="text">debugger </span>
</h1>
<p>
<span class="text">should </span>
<span class="post">be </span>
</p>
<p>
<span class="text">called </span>
<span class="post">ogle </span>
</p>
<h3>
<span class="statement">true</span>
</h3>
</body>
<html>
Objective
我愿意:
- 提取
<h1..."text"
的内容。 - 将提取的内容插入(并连接)到
<p..."text"
的内容中。 - 仅对 紧跟
<h1>
标签的<p>
标签执行此操作。 - 对页面上
<h1>
标签中的 所有 执行此操作。
再一次,一个例子可以更好地解释 ^this。这就是我想要的样子:
<html>
<body>
<p>
<span class="text">Go totally </span>
<span class="post">kicks </span>
</p>
<p>
<span class="text">hacks </span>
<span class="post">its </span>
</p>
<p>
<span class="text">debugger should </span>
<span class="post">be </span>
</p>
<p>
<span class="text">called </span>
<span class="post">ogle</span>
</p>
<h3>
<span class="statement">true</span>
</h3>
</body>
<html>
解决方案尝试
因为进一步区分 <h1>
标签和 <p>
标签会提供更多的解析选项,所以我想出了如何更改 <h1>
的 class
属性] 标签:
<html>
<body>
<h1>
<span class="title">Go </span>
</h1>
<p>
<span class="text">totally </span>
<span class="post">kicks </span>
</p>
<p>
<span class="text">hacks </span>
<span class="post">its </span>
</p>
<h1>
<span class="title">debugger </span>
</h1>
<p>
<span class="text">should </span>
<span class="post">be </span>
</p>
<p>
<span class="text">called </span>
<span class="post">ogle </span>
</p>
<h3>
<span class="statement">true</span>
</h3>
</body>
<html>
使用此代码:
html_code := strings.NewReader(`
code_example_above
`)
doc, _ := goquery.NewDocumentFromReader(html_code)
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
s.SetAttr("class", "title")
class, _ := s.Attr("class")
if class == "title" {
fmt.Println(class, s.Text())
}
})
我知道我可以 select <p..."text"
在 <h1..."title"
之后 doc.Find("h1+p")
或 s.Next()
在 doc.Find("h1").Each
函数内:
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
s.SetAttr("class", "title")
class, _ := s.Attr("class")
if class == "title" {
fmt.Println(class, s.Text())
fmt.Println(s.Next().Text())
}
})
我不知道如何插入从 <h1..."title"
到 <p..."text"
的文本。我已经尝试使用 s.After()
、s.Before()
和 s.Append()
的多种变体,例如:
doc.Find("h1").Each(func(i int, s *goquery.Selection) {
s.SetAttr("class", "title")
class, _ := s.Attr("class")
if class == "title" {
s.After(s.Text())
fmt.Println(s.Next().Text())
}
})
但我不知道如何做我想做的事。
如果我改用 s.After(s.Next().Text())
,我会得到这个错误输出:
panic: expected identifier, found 5 instead
goroutine 1 [running]:
code.google.com/p/cascadia.MustCompile(0xc2082f09a0, 0x62, 0x62)
/home/*/go/src/code.google.com/p/cascadia/selector.go:59 +0x77
github.com/PuerkitoBio/goquery.(*Selection).After(0xc2082ea630, 0xc2082f09a0, 0x62, 0x5)
/home/*/go/src/github.com/PuerkitoBio/goquery/manipulation.go:18 +0x32
main.func·001(0x0, 0xc2082ea630)
/home/*/go/test2.go:78 +0x106
github.com/PuerkitoBio/goquery.(*Selection).Each(0xc2082ea600, 0x7cb678, 0x2)
/home/*/go/src/github.com/PuerkitoBio/goquery/iteration.go:7 +0x173
main.ExampleScrape()
/home/*/go/test2.go:82 +0x213
main.main()
/home/*/go/test2.go:175 +0x1b
goroutine 9 [runnable]:
net/http.(*persistConn).readLoop(0xc208047ef0)
/usr/lib/go/src/net/http/transport.go:928 +0x9ce
created by net/http.(*Transport).dialConn
/usr/lib/go/src/net/http/transport.go:660 +0xc9f
goroutine 17 [syscall, locked to thread]:
runtime.goexit()
/usr/lib/go/src/runtime/asm_amd64.s:2232 +0x1
goroutine 10 [select]:
net/http.(*persistConn).writeLoop(0xc208047ef0)
/usr/lib/go/src/net/http/transport.go:945 +0x41d
created by net/http.(*Transport).dialConn
/usr/lib/go/src/net/http/transport.go:661 +0xcbc
exit status 2
(我的脚本的行与上面示例的行不匹配,但是我的脚本的 "line 72" 包含代码 s.After(s.Next().Text())
。我不知道具体是什么 panic: expected identifier, found 5 instead
表示。)
总结
总而言之,我的问题是我不太清楚如何使用 goquery
向标签添加文本。
我想我很接近。有地鼠绝地武士能够并愿意帮助这个学徒吗?
类似这段代码的工作,它找到所有 <h1>
个节点,然后找到这些 <h1>
个节点内的所有 <span>
个节点,寻找 class text
。然后它获取 <h1>
节点的下一个元素,如果它是一个 <p>
,里面有一个 <span>
,那么它将最后一个 <span>
替换为一个新的 <span>
与新文本并删除 <h1>
.
我想知道是否可以使用 goquery
创建节点而无需编写 html...
package main
import (
"fmt"
"strings"
"github.com/PuerkitoBio/goquery"
)
var htmlCode string = `<html>
...
<html>`
func main() {
doc, _ := goquery.NewDocumentFromReader(strings.NewReader((htmlCode)))
doc.Find("h1").Each(func(i int, h1 *goquery.Selection) {
h1.Find("span").Each(func(j int, s *goquery.Selection) {
if s.HasClass("text") {
if p := h1.Next(); p != nil {
if ps := p.Children().First(); ps != nil && ps.HasClass("text") {
ps.ReplaceWithHtml(
fmt.Sprintf("<span class=\"text\">%s%s</span>)", s.Text(), ps.Text()))
h1.Remove()
}
}
}
})
})
htmlResult, _ := doc.Html()
fmt.Println(htmlResult)
}