【问题标题】:How to get all text of a HTML document (except script/style/noscript tags) using Kuchiki?如何使用 Kuchiki 获取 HTML 文档的所有文本(script/style/noscript 标签除外)?
【发布时间】:2026-02-01 11:30:01
【问题描述】:

我正在尝试获取 HTML 页面上的所有文本,不可见文本除外(例如:我不想在 script/style/noscript 标记中显示文本)。

这是我到目前为止的想法:

let parser = kuchiki::parse_html().one(content);
for child in parser.inclusive_descendants() {
    if let Some(el) = child.as_element() {
        let tag_name = &el.name.local;
        if tag_name == "script" || tag_name == "style" || tag_name == "noscript" {
            child.detach();
        }
    }
}
let text = parser.text_contents();
println!("{}", text);

这个想法是第一遍将删除任何scriptstylenoscript 标记。然后我可以调用text_contents 来获取可见文本。

但是,text_contents 似乎仍在返回内联 Javascript。

我是否误解了 Kuchiki/html5ever API?

【问题讨论】:

    标签: html rust html5ever kuchiki


    【解决方案1】:

    inclusive_descendants() 迭代器似乎不喜欢迭代节点分离它们。

    鉴于以下情况:

    Cargo.toml

    [dependencies]
    kuchiki = "0.8.1"
    

    ma​​in.rs

    use kuchiki::traits::TendrilSink;
    
    let content = "\
        <html>\
        <head></head>\
        <body>\
            <div>div </div>\
            <script type='text/javascript'>script </script>\
            <noscript>noscript </noscript>\
            <span>span</span>\
        </body>\
        </html>";
    
    let parser = kuchiki::parse_html().one(content);
    
    for child in parser.inclusive_descendants() {
        if let Some(el) = child.as_element() {
            println!("{}", el.name.local);
        }
    }
    
    // println!("{}", parser.text_contents());
    

    我们得到所有节点:

    html
    head
    body
    div
    script
    noscript
    span
    

    当在迭代它们之后使用text_contents() 并像上面那样分离它们时,迭代器似乎在第一个分离节点之后失去了轨道:

    div noscript span
    

    它似乎也不依赖于标签的 type,因为切换 &lt;noscript&gt;&lt;script&gt; 标签的顺序给了我们:

    div script span
    

    我发现在首先收集它们之后分离节点似乎确实有效:

    parser
        .inclusive_descendants()
        .filter(|node| {
            node.as_element().map_or(false, |e| {
                matches!(e.name.local.as_ref(), "script" | "style" | "noscript")
            })
        })
        .collect::<Vec<_>>()
        .iter()
        .for_each(|node| node.detach());
    
    println!("{}", parser.text_contents());
    
    div span
    

    【讨论】: