如何使用Jsoup搜索注释("<!-- -->")?

20
我希望能够从源HTML中删除那些标签及其内容。
5个回答

43

在搜索时,您基本上使用 Elements.select(selector),其中selector此API定义。然而,评论在技术上不是元素,因此您可能会感到困惑,但它们仍然是由节点名称#comment标识的节点。

让我们看看它可能如何工作:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Node;

public class RemoveComments {
    public static void main(String... args) {
        String h = "<html><head></head><body>" +
          "<div><!-- foo --><p>bar<!-- baz --></div><!--qux--></body></html>";
        Document doc = Jsoup.parse(h);
        removeComments(doc);
        doc.html(System.out);
    }

    private static void removeComments(Node node) {
        for (int i = 0; i < node.childNodeSize();) {
            Node child = node.childNode(i);
            if (child.nodeName().equals("#comment"))
                child.remove();
            else {
                removeComments(child);
                i++;
            }
        }
    }        
}

2
如果您可以获得Jsoup的6年前版本,那么它在那时是有效的。否则,如果API已更新,我欢迎修复此示例以进行更新。看起来childNodes列表<node>在某个版本中被设置为不可修改。 - dlamblin
使用JSoup 1.11.3和Groovy...我需要做的唯一更改就是将childNodesSize()更改为childNodeSize(),这样它才能正常工作。 - Robert Hanson
@RobertHanson 谢谢,可能是一次转录错误。 - dlamblin
好的,但要注意文档对nodeName方法的说明:
获取此节点的节点名称。仅用于调试目的,而不是逻辑开关(对此,请使用instanceof)
因此,您应该使用 Comment.class.isInstance(child)
- Raf

3

使用JSoup 1.11+(可能也适用于旧版本),您可以应用过滤器:

private void removeComments(Element article) {
    article.filter(new NodeFilter() {
        @Override
        public FilterResult tail(Node node, int depth) {
            if (node instanceof Comment) {
                return FilterResult.REMOVE;
            }
            return FilterResult.CONTINUE;
        }

        @Override
        public FilterResult head(Node node, int depth) {
            if (node instanceof Comment) {
                return FilterResult.REMOVE;
            }
            return FilterResult.CONTINUE;
        }
    });
}

2

根据@dlamblin的答案,Java 8的函数式方法(抱歉,但这似乎比@Feuerrabe的答案更简单和清晰)

private void removeComments(Node node) {
    node.childNodes().stream().filter(n -> "#comment".equals(n.nodeName())).forEach(Node::remove);
    node.childNodes().forEach(this::removeComments);
}

Document doc = Jsoup.parse(html);
removeComments(doc);
// ...

优雅高效 - mvera

2

参考 @dlamblin https://dev59.com/oWsz5IYBdhLWcg3w9syr#7541875 这段代码可以获取评论的HTML。

public static void getHtmlComments(Node node) {
    for (int i = 0; i < node.childNodeSize();i++) {
        Node child = node.childNode(i);
        if (child.nodeName().equals("#comment")) {
            Comment comment = (Comment) child;
            child.after(comment.getData());
            child.remove();
        }
        else {
            getHtmlComments(child);
        }
    }
}

1
这是使用函数式编程方法的第一个示例的变体。找到当前节点的所有立即子节点中的所有注释的最简单方法是在 .childNodes() 流上使用 .filter()
public void removeComments(Element e) {
    e.childNodes().stream()
        .filter(n -> n.nodeName().equals("#comment")).collect(Collectors.toList())
        .forEach(n -> n.remove());
    e.children().forEach(elem -> removeComments(elem));
}

完整示例:

package demo;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.stream.Collectors;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
public class Demo {

public static void removeComments(Element e) {
    e.childNodes().stream()
        .filter(n -> n.nodeName().equals("#comment")).collect(Collectors.toList())
        .forEach(n -> n.remove());
    e.children().forEach(elem -> removeComments(elem));
}

public static void main(String[] args) throws MalformedURLException, IOException {
    Document doc = Jsoup.parse(new URL("https://en.wikipedia.org/"), 500);

    // do not try this with JDK < 8
    String userHome = System.getProperty("user.home");
    PrintStream out = new PrintStream(new FileOutputStream(userHome + File.separator + "before.html"));
    out.print(doc.outerHtml());
    out.close();

    removeComments(doc);
    out = new PrintStream(new FileOutputStream(userHome + File.separator + "after.html"));
    out.print(doc.outerHtml());
    out.close();
}

}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接