1

我有一个 Java 应用程序,它将解析 html 页面并从中提取数据。目前,我有一个类作为模板或说明如何阅读特定网页。该应用程序将需要从几个不同的站点读取,这些站点的格式将不同。我不想为每种格式创建一个新的模板类,而是希望能够读取随附的 XML 文件(或其他文档),该文件将提供有关哪些数据和提取位置的说明。

我试图在互联网上搜索如何做到这一点,但我猜我没有问正确的问题或使用正确的关键字。

该解决方案不必使用 XML 作为模板,但这是我的第一个想法。

谁能指出我正确的方向?

4

3 回答 3

2

您可以保留xpath表达式,而不是在 xml 中使用模板,这些表达式映射到您正在阅读的每个站点的所需数据。然后,随着您正在抓取的页面发生变化,您只需更新该站点的 xpath 表达式即可。

于 2012-11-08T23:28:06.887 回答
2

Extractor用于ExtractionInstructions从单一来源提取感兴趣的数据。您可以稍后从提取器中检索提取的数据。

在这个高级设计中

  • 来源:您要从中提取相同数据的每个页面
  • 提取器:每个提取在单个源上运行 1 个实例
  • ExtractionInstructions:一组指令,明确描述从单一来源提取数据的方法。
    • 您可以通过以下方式明确指定说明
      • 标签 ID 和/或
      • 使用 CSS 3 选择器和/或
      • xpath 等
    • 您可以通过将它们链接在一起(责任链模式)来使用上述所有方法的组合,以获得更多的成功百分比。想法是,如果使用 1 种提取类型找不到数据,那么您可以尝试使用其他选项,直到找到数据或用完说明为止)。

我建议使用JSoup作为基础库来构建这些抽象。

于 2012-11-08T23:37:55.893 回答
0

实际上我以前做过类似的事情,但它相当复杂。基本上我做了一个插件系统(像 Maven 一样恶心),你可以参数化提取插件。

您可以使用 Spring Bean XML 作为您的 DSL 来做到这一点。

<bean id="strategy1"  class="absolute.class.name">
</bean>

<bean id="extractorExecutor" class="class.to.extractorExecutor">
   <property name="strategies">
    <list>
        <item ref="strategy1" />
        <item ref="strategy2" />
     </list>
    </property> 
</bean>

您的提取器基本上循环通过实现如下接口的 bean:

public interface ExtractStrategy {
    /**
     * null means skip this extractor and go to the next one.
     */
    public Extracted extract(String data);
}

在您的提取器中,您可以:

for (ExtractorStrategy e : strategies) {
    Extracted ex = e.extract(data);
    if (ex != null) break;
}

Spring 将此称为解析器链模式,也有人将其称为策略模式。

然后,您可以制作像@digitaljoel 所说的 XPath 提取器和/或 Regex Extractor... 等。您将策略按照您希望它们运行的​​顺序排列。

在需要启发式的时,我一直使用这种模式。对于提取讨厌的 HTML(在您的评论中提到的其他人),我推荐JerichoJSoup(在这种情况下,您可以制定 Jericho 策略并添加到链中)。

于 2012-11-08T23:39:21.503 回答