使用jsoup库解析HTML元标记

19

我刚开始探索Jsoup库,因为我将在我的项目中使用它。我试图通过谷歌搜索找到能帮助我的确切答案,但未能如愿。这是我的问题,我有一个包含以下元标记的HTML文件

<meta content="this is the title value" name="d.title">
<meta content="this is the description value" name="d.description">
<meta content="language is french" name="d.language">

以下是一个Java POJO的示例:

public class Example {
    private String title;
    private String description;
    private String language;

    public Example() {}

    // setters and getters go here
} 

现在我想解析HTML文件,提取d.title内容值并存储在Example.title中,提取d.description内容值并存储在Example.description中等等。

我通过阅读jsoup cookbook已经完成了一些工作,类似于:

Document doc = Jsoup.parse("test.html");
Elements metaTags = doc.getElementsByTag("meta");

for (Element metaTag : metaTags) {
    String content = metaTag.attr("content");
    String content = metaTag.attr("name");
}
那将会遍历所有元标签,获取它们的“content”和“name”属性的值,但我想要获取“name”属性为“d.title”的“content”属性的值,以便将其存储在Example.title中。
更新:@P.J.Meisch下面的答案实际上解决了问题,但对于我来说那是太多的代码了(试图避免做完全相同的事情)。我的意思是,我认为可能可以像这样做:
String title = metaTags.getContent("d.title")
其中d.title是“name”属性的值。 这样将减少代码行数,我还没有找到这样的方法,但可能是因为我还是jsoup的新手,所以我问了。但是,如果不存在这样的方法(如果有这样的方法就太好了,因为它可以简化生活),我就会按照P.J.Meisch所说的去做。
4个回答

22

好的,所有代码:

Document doc = Jsoup.parse("test.html");
Elements metaTags = doc.getElementsByTag("meta");

Example ex = new Example();

for (Element metaTag : metaTags) {
  String content = metaTag.attr("content");
  String name = metaTag.attr("name");

  if("d.title".equals(name)) {
    ex.setTitle(content);
  }
  if("d.description".equals(name)) {
    ex.setDescription(content);
  }
  if("d.language".equals(name)) {
    ex.setLanguage(content);
  }
}

好的,我现在明白你的回答了。谢谢。但是我希望不要采取那样的方法。我会更新我的问题以反映我实际想要的内容。 :) - ivange
我更新了我的问题,你能看一下并确认一下我想要的是否可行吗? - ivange
我最初批准了您使用映射的其他答案,但我意识到它不会很好地工作,因为我正在处理的HTML文件具有出现多次的名称属性(例如d.contributor可能会出现多次),如果我使用映射来存储它们,映射将仅存储最后一个,因为它不能具有引用不同对象的相同键。所以我只是按照这个做了。 - ivange
地图仅具有元标记的名称属性作为键,而不是其他具有名称元素的标记的名称属性,因此应该可以工作。 - P.J.Meisch
我所说的是一些名称属性具有相同的值,例如可能会有多个d.contributor作为名称。而该映射将名称属性存储为键,这种情况下是"d.contributor",它出现了3次,因此该映射只会存储最后一个。 - ivange

4

回答您的更新问题:使用jsoup是不可能实现的,因为jsoup文档只反映了HTML文档的XML/DOM结构。您需要自己迭代元数据,但可以尝试以下方法:

Document doc = Jsoup.parse("test.html");

Map<String, String> metas = new HashMap<>();
Elements metaTags = doc.getElementsByTag("meta");

for (Element metaTag : metaTags) {
  String content = metaTag.attr("content");
  String name = metaTag.attr("name");
  metas.put(name, content);
}

Example ex = new Example();
ex.setTitle(metas.get("d.title"));
ex.setDescription(metas.get("d.description"));
ex.setLanguage(metas.get("d.language"));

谢谢。这是我想要的最接近的东西。不过如果jsoup有那个功能会很好,因为它是开源的,我会尝试看看能否实现它 :) - ivange

1

使用正确的特定库可以简化一切

查看我的用于解析元标记内容的库

poshjosh/bcmetaselector

package com.bc.meta.selector;

import com.bc.meta.selector.htmlparser.AttributeContextHtmlparser;
import com.bc.meta.selector.util.SampleConfigPaths;
import com.bc.meta.ArticleMetaNames;
import com.bc.meta.impl.ArticleMetaNameIsMultiValue;
import java.util.Map;
import java.util.Iterator;
import java.util.function.BiFunction;
import org.json.simple.JSONValue;
import org.htmlparser.Parser;
import org.htmlparser.Node;
import org.htmlparser.Tag;

public class ReadMe {

    public static void main(String... args) throws Exception {

        final BiFunction<String, Node, String> nodeContentExtractor =
                (prop, node) -> node instanceof Tag ? ((Tag)node).getAttributeValue("content") : null;

        final SelectorBuilder<Node, String, Object> builder = Selector.builder();

        final Selector<Node> selector = builder.filter()
                .attributeContext(new AttributeContextHtmlparser(false))
                .configFilePaths(SampleConfigPaths.APP_ARTICLE_LIST)
                .jsonParser((reader) -> (Map)JSONValue.parse(reader))
                .propertyNames(ArticleMetaNames.values())
                .back()
                .multipleValueTest(new ArticleMetaNameIsMultiValue())
                .nodeConverter(nodeContentExtractor)
                .build();

        final Parser parser = new Parser();

        final String url = "https://edition.cnn.com/2018/06/21/africa/noura-hussein-asequals-intl/index.html";

        parser.setURL(url);

        Iterator<Node> nodes = parser.elements().iterator();

        final Map map = selector.selectAsMap(nodes, ArticleMetaNames.values());

        System.out.println("Printing meta tags data for: " + url + "\n" + map);
    }
}

0

你将这两个属性的值都赋给了名为 content 的变量。将 name 属性赋给一个名为 name 的变量,并将其与你期望的值 'd.title' 进行比较。


我怎么知道所需的d.title值。HTML文件不是由我生成的,因此我事先不知道“d.title”的值。 - ivange

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