使用Apache Tika提取表格信息是否可行?

10

我正在寻找一种用于解析PDF和MS Office文档格式的分析器,以从文件中提取表格信息。当我看到Apache Tika时,我正在考虑编写单独的实现。我能够从这些文件格式中提取完整的文本。但我的要求是提取表格数据,其中我期望以键值格式呈现2列。我检查了网络上大多数可用的解决方案,但没有找到任何可以解决问题的提示。

4个回答

8

我已经使用Apache POI分别实现了MS格式的内容,然后回到Tika处理PDF。Tika处理文档的方式是将其输出为"SAX基于XHTML事件"1

因此,我们可以编写自定义SAX实现来解析文件。

结构化文本输出的形式为(避免元数据):

<body><div class="page"><p/>
<p>Key1 Value1 </p>
<p>Key2 Value2 </p>
<p>Key3 Value3</p>
<p/>
</div>
</body>

在我们的SAX实现中,我们可以将第一部分视为关键字(对于我的问题,我已经知道了关键字,正在寻找值,所以它是一个子字符串)。
使用以下逻辑覆盖公共void字符(char [] ch,int start,int length):
请注意,对于我的情况,内容的结构是固定的,我知道即将到来的关键字,所以用这种方式很容易。这不是通用解决方案。

嗨,Rajesh,一年后我也遇到了与你相同的问题 :) 我想知道是否有通用解决方案来解决这个问题。在我的情况下,pdf文件将包含任何类型的表格结构,我必须确保表格被正确提取,并尽可能注释表格标题。是否可以使用Tika来完成?或者是否有其他API可以做到这一点? - Shekhar
1
@Shekhar,我没有得到任何通用的解决方案。基本上,您应该能够在MS格式中完成此操作,但我怀疑PDF是否可行(请参阅:https://dev59.com/nGHVa4cB1Zd3GeqPpryd#9803283。同一线程具有一些Python解决方案,如果您知道表格标题,则可能有效。我自己没有尝试过)。 - rajesh

8
Tika不解析表格信息。实际上,令人困惑的部分是它将表格标签转换为<p>标签,这意味着我们失去了结构。直到目前版本1.14都是这种情况。未来可能会解决这个问题,但目前没有计划朝这个方向努力。
您可以参考JIRA中对Tika这个缺陷的讨论。 在JIRA之后,wiki也进行了更新,以反映这个缺陷。[免责声明:我提出了JIRA]
现在是解决方案:根据我的经验,Aspose.Pdf for Java非常出色地将PDF转换为HTML。但它需要付费购买许可证。您可以通过免费试用版检查其质量。代码和示例链接

Tabula(http://tabula.technology/)是一种免费的、MIT许可证授权的选项,用于从PDF中提取表格。如果您希望我们将其与Tika集成,请在我们的JIRA上开启一个问题。 - Tim Allison

2
我使用tika (tika-app-1.19.jar) 和aspose (aspose-pdf-18.9.1.jar) 的组合...
我首先使用Aspose修改pdf文件,在表格列末尾添加竖线('|')... ...然后将其读入Tika并转换为文本...
InputStream is = part.getInputStream(); // input-stream of PDF or PDF part

// Aspose add pipes ("|")
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
Document pdfDocument   = new Document(is);   // load existing PDF file

PageCollection pageCollection = pdfDocument.getPages();
int iNumPages = pageCollection.size();

for(int i = 1; i <= iNumPages; i++)
{
    Page page = pageCollection.get_Item(i);
    TableAbsorber absorber = new TableAbsorber();// Create TableAbsorber object to find tables
    absorber.visit(page);// Visit first page with absorber

    IGenericList<AbsorbedTable> listTables = absorber.getTableList();

    for(AbsorbedTable absorbedTable : listTables)
    {
        IGenericList<AbsorbedRow> listRows = absorbedTable.getRowList();

        for(AbsorbedRow absorbedRow : listRows)
        {
            IGenericList<AbsorbedCell> listCells = absorbedRow.getCellList();

            for(AbsorbedCell absorbedCell : listCells)
            {
                TextFragmentCollection  collectionTextFrag = absorbedCell.getTextFragments();

                Rectangle rectangle = absorbedCell.getRectangle();

                // Add pipes ("|") to indicate table ends
                TextBuilder  textBuilder  = new TextBuilder(page);
                TextFragment textFragment = new TextFragment("|");
                double x = rectangle.getURX();
                double y = rectangle.getURY();
                textFragment.setPosition(new Position(x, y));
                textBuilder.appendText(textFragment);
            }
        }
    }
}
pdfDocument.save(outputStream);
is = new ByteArrayInputStream(outputStream.toByteArray()); // input-steam of modified PDF with pipes included ("|")

现在,可以将带有管道符号(“|”)的表格单元格末尾的PDF输入流传入Tika并转换为文本...
BodyContentHandler handler   = new BodyContentHandler();
Metadata           metadata  = new Metadata();
ParseContext       context   = new ParseContext();
PDFParser          pdfParser = new PDFParser();

PDFParserConfig config = pdfParser.getPDFParserConfig();
config.setSortByPosition(true); // needed for text in correct order
pdfParser.setPDFParserConfig(config);

//InputStream stream = new ByteArrayInputStream(sIS.getBytes(StandardCharsets.UTF_8));
pdfParser.parse(is, handler, metadata, context);
String sPdfData = handler.toString();

0

我在这里找到了一篇非常有用的博客文章,它使用ContentHandlerDecorator(使用Groovy,但足够相似)解析表格: https://opensource.com/article/17/8/tika-groovy

我将其改编为仅将所有<td>部分解析为制表符分隔行,并通过跟随<tr>标记将行收集到列表中,因为我需要表格行保持完整,但不需要表格单元格内的特殊逻辑。

您可以将您的装饰器传递给BodyHandler,它将其包装为委托,如下所示:

new AutoDetectParser().parse(inputStream,
    new BodyContentHandler(new MyContentHandlerDecorator()),
    new Metadata());

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