使用Java将PDF转换为CSV

6

我尝试了Stack Overflow和外部的大多数解决方案。

问题: 我有一个包含内容和表格的pdf文件。 我需要解析表格和内容。

APIs: https://github.com/tabulapdf/tabula-java 我正在使用tabula-java,但它忽略了一些内容,并且表格单元格内的内容没有以正确的方式分离。

我的PDF文档具有以下内容:

 DATE :1/1/2018         ABCD                   SCODE:FFFT
                       --ACCEPTED--
    USER:ADMIN         BATCH:RR               EEE
    CON BATCH
    =======================================================================
    MAIN SNO SUB  VALUE DIS %
    R    12   rr1 0125  24.5
            SLNO  DESC  QTY  TOTAL  CODE   FREE
            1     ABD   12   90     BBNEW  -NILL-
            2     XDF   45   55     GHT55  MRP
            3     QWE   08   77     CAT    -NILL-
    =======================================================================
    MAIN SNO SUB  VALUE DIS %
    QW    14   rr2 0122  24.5
            SLNO  DESC  QTY  TOTAL  CODE   FREE
            1     ABD   12   90     BBNEW  -NILL-
            2     XDF   45   55     GHT55  MRP
            3     QWE   08   77     CAT    -NILL-

用Tabula代码进行转换:

public static void toCsv() throws ParseException {
        String commandLineOptions[] = { "-p", "1", "-o", "$csv", };
        CommandLineParser parser = new DefaultParser();
        try {
            CommandLine line = parser.parse(TabulaUtil.buildOptions(), commandLineOptions);
            new TabulaUtil(System.out, line).extractFileInto(
                    new File("/home/sample/firstPage.pdf"),
                    new File("/home/sample/onePage.csv"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

tabula甚至支持命令行界面

java -jar TabulaJar/tabula-1.0.2-jar-with-dependencies.jar -p all  -o  $csv -b Pdfs

我尝试使用tabula的-c,--columns <COLUMNS>选项,该选项按列边界的X坐标获取单元格。但问题是我的PDF内容是动态的,即表格大小随时间而变化。在Stack Overflow上有很多解决方案,但都不适用于我。
以下是这些解答: 如何使用tabula-py将PDF转换为CSV? 如何从命令行中提取PDF表格数据并转换为CSV? 在Java中将PDF转换为Excel 如何将PDF文件转换为CSV文件? iText将PDF转换为CSV 解析PDF表格并将其显示为CSV(Java) 我已经尝试过使用PDF Box,但由于其提供的文本格式不规范,导致无法正确读取表格内容。
是否可能在Java中将带有表格的PDF转换为CSV / Excel而不会丢失内容和格式? 我不想使用收费的库。

我认为在PDF文档中任何表格都不可能实现。这些方法在某种程度上显然存在局限性,因为表格可以具有嵌套的列和行,例如使用latex的multicolumn包等。您是否有一个到目前为止无法工作的PDF示例? - UninformedUser
1
我认为根据你的发现,到达最终CSV的整个过程都是虚幻的。显示PDF,您的尝试以及修复/确认步骤似乎是最可行的解决方案。 - Joop Eggen
我同意@AKSW和@Joop Eggen的观点,但有一件事情让我困惑,那就是这个API如何能够完美地转换嵌套表格和内容。https://pdftables.com是一个付费的工具,这意味着有一种方法可以实现。我想知道怎么做? - KishanCS
1
你知道,商业软件之所以商业,通常是因为在其上花费了更多的精力。只有那些了解商业API代码并将其与开源项目进行比较的人才能告诉你原因。我的意思是,它是开源的 - 你也可以深入代码并扩展它。或者问问开发人员。但不要忘记,人们可能只是为了他们非常受限制的需求而这样做,并且你可能得不到任何支持。 - UninformedUser
如果您正在寻找商业工具,我建议您也看一下iText的pdf2Data。它还可以从表格等中提取内容。 - Aykut Avci
2个回答

0

0

在这里可以查看使用Java将PDF提取为CSV的任何示例:https://github.com/pdftables/java-pdftables-api。每个页面都被视为独立的,因此您的PDF的动态性不应成为问题。您可以在他们的网站上使用免费试用版。

package com.pdftables.examples;

import java.io.File;
import java.util.Arrays;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.http.HttpEntity;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

public class ConvertToFile {
    private static List<String> formats = Arrays.asList(new String[] { "csv", "xml", "xlsx-single", "xlsx-multiple" });

    public static void main(String[] args) throws Exception {
        if (args.length != 3) {
            System.out.println("Command line: <API_KEY> <FORMAT> <PDF filename>");
            System.exit(1);
        }

        final String apiKey = args[0];
        final String format = args[1].toLowerCase();
        final String pdfFilename = args[2];

        if (!formats.contains(format)) {
            System.out.println("Invalid output format: \"" + format + "\"");
            System.exit(1);
        }

        // Avoid cookie warning with default cookie configuration
        RequestConfig globalConfig = RequestConfig.custom().setCookieSpec(CookieSpecs.STANDARD).build();

        File inputFile = new File(pdfFilename);

        if (!inputFile.canRead()) {
            System.out.println("Can't read input PDF file: \"" + pdfFilename + "\"");
            System.exit(1);
        }

        try (CloseableHttpClient httpclient = HttpClients.custom().setDefaultRequestConfig(globalConfig).build()) {
            HttpPost httppost = new HttpPost("https://pdftables.com/api?format=" + format + "&key=" + apiKey);
            FileBody fileBody = new FileBody(inputFile);

            HttpEntity requestBody = MultipartEntityBuilder.create().addPart("f", fileBody).build();
            httppost.setEntity(requestBody);

            System.out.println("Sending request");

            try (CloseableHttpResponse response = httpclient.execute(httppost)) {
                if (response.getStatusLine().getStatusCode() != 200) {
                    System.out.println(response.getStatusLine());
                    System.exit(1);
                }
                HttpEntity resEntity = response.getEntity();
                if (resEntity != null) {
                    final String outputFilename = getOutputFilename(pdfFilename, format.replaceFirst("-.*$", ""));
                    System.out.println("Writing output to " + outputFilename);

                    final File outputFile = new File(outputFilename);
                    FileUtils.copyToFile(resEntity.getContent(), outputFile);
                } else {
                    System.out.println("Error: file missing from response");
                    System.exit(1);
                }
            }
        }
    }

    private static String getOutputFilename(String pdfFilename, String suffix) {
        if (pdfFilename.length() >= 5 && pdfFilename.toLowerCase().endsWith(".pdf")) {
            return pdfFilename.substring(0, pdfFilename.length() - 4) + "." + suffix;
        } else {
            return pdfFilename + "." + suffix;
        }
    }
}

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