我希望能够从源HTML中删除那些标签及其内容。
在搜索时,您基本上使用 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++;
}
}
}
}
使用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;
}
});
}
根据@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);
// ...
参考 @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);
}
}
}
.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();
}
}
nodeName
方法的说明:获取此节点的节点名称。仅用于调试目的,而不是逻辑开关(对此,请使用instanceof)
因此,您应该使用
Comment.class.isInstance(child)
。 - Raf