我面临的问题是,即使仅尝试 200 个请求也会导致程序占用容器的 6gb 内存并最终被 oom 杀死。 我的想法是提取 html 中存在的所有文本节点,然后处理它们以提取它们的名称、该标签的 html 和文本。因此,为了生成特定标签的 html,我使用 golang.org/x/net/html 中的 render 函数。其中我提供 strings.builder 作为 io.writer 来编写生成的 html。但由于某种原因,构建器占用了太多内存。
package main
import (
"encoding/csv"
"io"
"log"
"net/http"
"strings"
"golang.org/x/net/html"
)
func main() {
mux := http.NewServeMux()
mux.HandleFunc("/data", GetData)
if err := http.ListenAndServe(":8001", mux); err != nil {
log.Println(err)
}
}
type TagInfo struct {
Tag string
Name string
Text string
}
// http.handler
func GetData(w http.ResponseWriter, r *http.Request) {
u := r.URL.Query().Get("url")
doc, err := GetDoc(u)
if err != nil {
log.Println(err)
w.WriteHeader(500)
return
}
var buf strings.Builder
data := Extract(doc, &buf)
csvw := csv.NewWriter(io.Discard)
for _, d := range data {
csvw.Write([]string{d.Name, d.Tag, d.Text})
}
}
// fires request and get text/html
func GetDoc(u string) (*html.Node, error) {
res, err := http.Get(u)
if err != nil {
return nil, err
}
defer res.Body.Close()
return html.Parse(res.Body)
}
func Extract(doc *html.Node, buf *strings.Builder) []TagInfo {
var (
tags = make([]TagInfo, 0, 100)
f func(*html.Node)
)
f = func(n *html.Node) {
if n.Type == html.TextNode {
text := strings.TrimSpace(n.Data)
if text != "" {
parent := n.Parent
tag := Render(parent, buf)
tagInfo := TagInfo{
Tag: tag,
Name: parent.Data,
Text: n.Data,
}
tags = append(tags, tagInfo)
}
}
for child := n.FirstChild; child != nil; child = child.NextSibling {
f(child)
}
}
f(doc)
return tags
}
// Render the html around the tag
// if node is text then pass the
// parent node paramter in function
func Render(n *html.Node, buf *strings.Builder) string {
defer buf.Reset()
if err := html.Render(buf, n); err != nil {
log.Println(err)
return ""
}
return buf.String()
}
如果您想要特定的网址列表,这里就是。我一次发出了大约 60 个请求。
我尝试使用 bytes.buffer bytes.buffer
和 sync.pool
但两者都有相同的问题。使用 pprof
我注意到 strings.builder 的 writestring
方法导致大量内存使用。
正确答案
所以这里的基本问题是接受任何 content-type
,这在抓取方面是不可接受的,大多数网站都需要发送 text/html
。
问题是即使url发送任何不代表html数据的内容golang.org/x/net/html
仍然接受它而不抛出错误。
让我们举一个例子,其中返回 application/pdf
,然后正文将包含 html.Parse
解析的 pdf 的二进制数据,并且不会返回任何错误,这是用于抓取/爬行接受二进制数据的奇怪行为思维库。
解决方案是:检查响应头,如果只有数据是html,然后继续,否则会出现歧义或更高的内存使用量(可能更低),但我们无法预测会发生什么发生。
以上就是html 渲染函数内存泄漏的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
软考中级精品资料免费领
- 历年真题答案解析
- 备考技巧名师总结
- 高频考点精准押题
- 资料下载
- 历年真题
193.9 KB下载数265
191.63 KB下载数245
143.91 KB下载数1148
183.71 KB下载数642
644.84 KB下载数2756