使用Jsoup删除不包含其自身文本的节点

时间:2019-06-03 20:17:22

标签: java web-scraping jsoup

我注意到很多网页都有多余的(出于我的目的)html节点。我想将其从页面中删除,因为这样可以使我的处理更加容易。

是否可以使用JSoup做到这一点?

为使情况更加清晰,我们有以下页面:

<html>
  <head>
  </head>
  <body>
    <div>I have some text</div>
    <div class='useless'>
      <div class='useless'>
        <div>I also have text
          <div>I also have text</div>
        </div>
      </div>   
    </div>      
  </body>
</html>

我想删除class ='useless'div-但是我当然不能仅通过它们的内容/内容来根据它们的class / id / tag等选择它们。当然,这将更改页面的结构,这完全没问题-这将使我的最终处理更加容易。

结果将是:

<html>
  <head>
  </head>
  <body>
    <div>I have some text</div>
    <div class='useless'>
      <div class='useless'>
        <div>I also have text
          <div>I also have text</div>
        </div>
      </div>
    </div>   
  </body>
</html>

这是通过简单还是困难的方式实现的?

结果将是:

<html>
  <head>
  </head>
  <body>
    <div>I have some text</div>
    <div>I also have text
      <div>I also have text</div>
    </div>  
  </body>
</html>

现在我想不出任何特别优雅的东西。我的一般倾向是检查各种元素上的ownText()方法(将检查ownText().length() > 0),以及是否false尝试删除它们,但我认为这会删除所有子元素/子元素即使它们在true条件下与.ownText()相匹配。

1 个答案:

答案 0 :(得分:1)

您可以使用Document.getAllElements()并检查每个元素是否具有ownText()。如果什么也没做。如果没有,则将所有子节点附加到父节点(如果有)。这应该可以完成工作:

Document document = Jsoup.parse(html);
document.getAllElements().stream()
        .filter(e -> e.ownText().isEmpty())
        .filter(Element::hasParent)
        .forEach(e -> {
            e.children().forEach(e.parent()::appendChild);
            e.remove();
        });

您共享的代码的结果将是这样:

<div>
 I have some text
</div>
<div>
 I also have text 
 <div>
  I also have text
 </div> 
</div>

正如我在评论中提到的,您的ownText()规则也应删除htmlheadbody元素。


如果要防止删除某些特殊标签,可以使用简单的SetList,其中包含标签名称,应保留以下名称:

Set<String> retainTagNames = new HashSet<>(Arrays.asList("html", "body"));
Document document = Jsoup.parse(html);
document.getAllElements().stream()
        .filter(e -> ! retainTagNames.contains(e.tagName()))
        .filter(e -> e.ownText().isEmpty())
        .filter(Element::hasParent)
        .forEach(e -> {
            e.children().forEach(e.parent()::appendChild);
            e.remove();
        });

其结果将是:

<html>
 <head> 
 </head> 
 <body> 
  <div>
   I have some text
  </div>   
  <div>
   I also have text 
   <div>
    I also have text
   </div> 
  </div>
 </body>
</html>