使用PDFBox解析PDF文件(尤其是表格)

Mat*_*ira 63 java pdf parsing tabular pdfbox

我需要解析包含表格数据的PDF文件.我正在使用PDFBox提取文件文本以便稍后解析结果(String).问题是文本提取不像我预期的表格数据那样工作.例如,我有一个包含这样的表的文件(7列:前两个总是有数据,只有一个Complexity列有数据,只有一个Financing列有数据):

+----------------------------------------------------------------+
| AIH | Value | Complexity                     | Financing       |
|     |       | Medium | High | Not applicable | MAC/Other | FAE |
+----------------------------------------------------------------+
| xyz | 12.43 | 12.34  |      |                | 12.34     |     |
+----------------------------------------------------------------+
| abc | 1.56  |        | 1.56 |                |           | 1.56|
+----------------------------------------------------------------+
Run Code Online (Sandbox Code Playgroud)

然后我使用PDFBox:

PDDocument document = PDDocument.load(pathToFile);
PDFTextStripper s = new PDFTextStripper();
String content = s.getText(document);
Run Code Online (Sandbox Code Playgroud)

这两行数据将被提取如下:

xyz 12.43 12.4312.43
abc 1.56 1.561.56
Run Code Online (Sandbox Code Playgroud)

最后两个数字之间没有空格,但这不是最大的问题.问题是我不知道最后两个数字是什么意思:中,高,不适用?MAC /其他,FAE?我没有数字和列之间的关系.

我不需要使用PDFBox库,因此使用另一个库的解决方案很好.我想要的是能够解析文件并知道每个解析的数字意味着什么.

pur*_*ger 18

您需要设计一种算法来以可用的格式提取数据.无论您使用哪个PDF库,都需要执行此操作.字符和图形由一系列有状态绘制操作绘制,即移动到屏幕上的此位置并绘制字符'c'的字形.

我建议你扩展org.apache.pdfbox.pdfviewer.PDFPageDrawer并覆盖该strokePath方法.从那里,您可以截取水平和垂直线段的绘制操作,并使用该信息确定表的列和行位置.然后简单的设置文本区域并确定在哪个区域中绘制哪些数字/字母/字符.由于您知道区域的布局,因此您将能够分辨提取的文本所属的列.

此外,您在视觉上分开的文本之间可能没有空格的原因通常是PDF不会绘制空格字符.而是更新文本矩阵并发出"移动"的绘图命令以绘制下一个字符和除最后一个字符之外的"空间宽度".

祝好运.


Tho*_*Tho 12

我曾经使用过很多工具从pdf文件中提取表格,但它对我不起作用.

所以我已经实现了我自己的算法(它的名字traprange)来解析pdf文件中的表格数据.

以下是一些示例pdf文件和结果:

  1. 输入文件:sample-1.pdf,result:sample-1.html
  2. 输入文件:sample-4.pdf,result:sample-4.html

访问我在traprange的项目页面.


imp*_*eto 11

我的答案可能为时已晚,但我认为这并不难.您可以扩展PDFTextStripper类并覆盖writePage()和processTextPosition(...)方法.在您的情况下,我假设列标题始终相同.这意味着您知道每个列标题的x坐标,并且可以将数字的x坐标与列标题的x坐标进行比较.如果它们足够接近(您必须测试以确定接近程度),那么您可以说该数字属于该列.

另一种方法是在每个页面写入后截取"charactersByArticle"向量:

@Override
public void writePage() throws IOException {
    super.writePage();
    final Vector<List<TextPosition>> pageText = getCharactersByArticle();
    //now you have all the characters on that page
    //to do what you want with them
}
Run Code Online (Sandbox Code Playgroud)

了解了您的列,您可以对x坐标进行比较,以确定每个数字所属的列.

数字之间没有空格的原因是你必须设置单词分隔符字符串.

我希望这对你或其他可能尝试类似事情的人有用.


Eme*_*gia 11

您可以在PDFBox中按区域提取文本.如果您正在使用Maven ExtractByArea.java,请参阅pdfbox-examples工件中的示例文件.一个片段看起来像

   PDFTextStripperByArea stripper = new PDFTextStripperByArea();
   stripper.setSortByPosition( true );
   Rectangle rect = new Rectangle( 464, 59, 55, 5);
   stripper.addRegion( "class1", rect );
   stripper.extractRegions( page );
   String string = stripper.getTextForRegion( "class1" );
Run Code Online (Sandbox Code Playgroud)

问题是首先得到坐标.我已经成功地扩展了法线TextStripper,覆盖processTextPosition(TextPosition text)并打印出每个角色的坐标,并找出它们在文档中的位置.

但是有一个更简单的方法,至少如果你在Mac上.在预览中打开PDF,⌘I显示检查器,选择裁剪选项卡并确保单位在点中,从工具菜单中选择矩形选择,然后选择感兴趣的区域.如果选择一个区域,检查器将显示坐标,您可以将其舍入并输入Rectangle构造函数参数.您只需要使用第一种方法确认原点的位置.

  • 当 PDF 具有固定布局时,很好,简单的解决方案!对于在 macOS 中使用预览的技巧,我会再次投票(如果可以的话!)。使提取非常容易。 (2认同)

Mat*_*aun 8

PDFLayoutTextStripper,旨在保持数据的格式.

来自README:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.util.PDFTextStripper;

public class Test {

    public static void main(String[] args) {
        String string = null;
        try {
            PDFParser pdfParser = new PDFParser(new FileInputStream("sample.pdf"));
            pdfParser.parse();
            PDDocument pdDocument = new PDDocument(pdfParser.getDocument());
            PDFTextStripper pdfTextStripper = new PDFLayoutTextStripper();
            string = pdfTextStripper.getText(pdDocument);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        };
        System.out.println(string);
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 使用当前版本的 pdfbox , `PDFParser` 实例创建需要更改为 - `PDFParser pdfParser = new PDFParser( new RandomAccessBufferedFileInputStream( "sample.pdf"));` (2认同)

sco*_*ott 5

我在解析pdftotext实用程序(sudo apt-get install poppler-utils)生成的文本文件方面取得了相当大的成功。

File convertPdf() throws Exception {
    File pdf = new File("mypdf.pdf");
    String outfile = "mytxt.txt";
    String proc = "/usr/bin/pdftotext";
    ProcessBuilder pb = new ProcessBuilder(proc,"-layout",pdf.getAbsolutePath(),outfile); 
    Process p = pb.start();

    p.waitFor();

    return new File(outfile);
}
Run Code Online (Sandbox Code Playgroud)


Pau*_*ald -1

我不熟悉 PDFBox,但你可以尝试查看itext。尽管主页上说生成 PDF,但您也可以进行 PDF 操作和提取。看一下它是否适合您的用例。