如何从命令行将PDF中的表格数据提取为CSV?

如何从命令行将PDF中的表格数据提取为CSV?,pdf,grep,pdftotext,Pdf,Grep,Pdftotext,我想从中提取所有行,同时忽略列标题和所有页面标题,即支持的设备 pdftotext -layout DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - \ | sed '$d' \ | sed -r 's/ +/,/g; s/ //g' \ > output.csv 生成的文件应为CSV电

我想从中提取所有行,同时忽略列标题和所有页面标题,即
支持的设备

pdftotext -layout DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - \
 | sed '$d'                                                  \
 | sed -r 's/ +/,/g; s/ //g'                                 \
 > output.csv
生成的文件应为CSV电子表格格式(逗号分隔的值字段)


换句话说,我想改进上面的命令,这样输出就不会停止。有什么想法吗?

你想要的东西很容易,但你也有不同的问题(我不确定你是否意识到…)

首先,您应该在命令中添加
-nopgbrk
for(“请不要分页符!”)。因为这些讨厌的
^L
字符出现在输出中,以后不需要过滤掉

添加一个
grep-vE'(支持的设备|^$)
将过滤掉所有您不需要的行,包括空行或只有空格的行:

pdftotext -layout -nopgbrk                           \
   DAC06E7D1302B790429AF6E84696FCFAB20B.pdf -        \
 | grep -vE '(Supported Devices|^$|Marketing Name)'  \
 | gsed '$d'                                         \
 | gsed -r 's# +#,#g'                                \
 | gsed '# ##g'                                      \
 > output2.csv
但是,您的另一个问题是:

  • 某些表字段为空
  • 空字段与
    -layout
    选项一起显示为一系列空格字符,有时甚至是同一行中的两个空格字符
  • 但是,文本列在每页之间的间距并不相同
  • 因此,您将无法逐行知道需要将多少空格视为“空CSV字段”(其中需要额外的
    分隔符)
  • 因此,对于某些行,您当前的代码将只显示一个、两个或三个(而不是四个)字段,而这些字段最终会出现在错误的列中 有一个解决方法:

  • 添加
    -x-y-W-H…
    parameters to
    pdftotext
    以按列裁剪PDF
  • 然后使用诸如
    paste
    column
    之类的实用程序组合来追加列
  • 以下命令提取第一列:

    pdftotext -layout -x  38 -y 77 -W 176 -H 500  \
              DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - > 1st-columns.txt
    
    这些是第二、第三和第四列:

    pdftotext -layout -x 214 -y 77 -W 176 -H 500  \
              DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - > 2nd-columns.txt
    
    pdftotext -layout -x 390 -y 77 -W 176 -H 500  \
              DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - > 3rd-columns.txt
    
    pdftotext -layout -x 567 -y 77 -W 176 -H 500  \
              DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - > 4th-columns.txt
    
    顺便说一句,我有点作弊:为了得到关于
    -x
    -y
    -W
    -H
    使用哪些值的线索,我首先运行了这个命令,以便找到列标题词的精确坐标:

    pdftotext -f 1 -l 1 -layout -bbox \
              DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - | head -n 10
    
    如果您知道如何阅读和使用
    pdftotext-h
    :-),这总是很好的


    无论如何,如何将这四个文本文件作为列并排附加,并在它们之间使用适当的CVS分隔符,您应该了解一下。或者问一个新问题:-)

    我也会为您提供另一个解决方案

    虽然在这种情况下,
    pdftotext
    方法可以合理地工作,但也有可能不是每个页面都有相同的列宽(如您的良性PDF所示)

    在这里,不是很有名,但是很酷的免费开源软件是最好的选择

    我本人正在使用直接GitHub签出:

    $ cd $HOME ; mkdir svn-stuff ; cd svn-stuff
    $ git clone https://github.com/tabulapdf/tabula-extractor.git git.tabula-extractor
    
    我为自己编写了一个非常简单的包装器脚本,如下所示:

    $ cat ~/bin/tabulaextr
    
     #!/bin/bash
     cd ${HOME}/svn-stuff/git.tabula-extractor/bin
     ./tabula $@
    
    $ head DAC06E7D1302B790429AF6E84696FCFAB20B.csv 
    
     Retail Branding,Marketing Name,Device,Model
     "","",AD681H,Smartfren Andromax AD681H
     "","",FJL21,FJL21
     "","",Luno,Luno
     "","",T31,Panasonic T31
     "","",hws7721g,MediaPad 7 Youth 2
     3Q,OC1020A,OC1020A,OC1020A
     7Eleven,IN265,IN265,IN265
     A.O.I. ELECTRONICS FACTORY,A.O.I.,TR10CS1_11,TR10CS1
     AG Mobile,Status,Status,Status
    
    因为
    ~/bin/
    在我的
    $PATH
    中,所以我只运行

    $ tabulaextr --pages all                                 \
             $(pwd)/DAC06E7D1302B790429AF6E84696FCFAB20B.pdf \
            | tee my.csv
    
    从所有页面提取所有表格并将其转换为单个CSV文件

    CV的前十行(总共8727行)如下所示:

    $ cat ~/bin/tabulaextr
    
     #!/bin/bash
     cd ${HOME}/svn-stuff/git.tabula-extractor/bin
     ./tabula $@
    
    $ head DAC06E7D1302B790429AF6E84696FCFAB20B.csv 
    
     Retail Branding,Marketing Name,Device,Model
     "","",AD681H,Smartfren Andromax AD681H
     "","",FJL21,FJL21
     "","",Luno,Luno
     "","",T31,Panasonic T31
     "","",hws7721g,MediaPad 7 Youth 2
     3Q,OC1020A,OC1020A,OC1020A
     7Eleven,IN265,IN265,IN265
     A.O.I. ELECTRONICS FACTORY,A.O.I.,TR10CS1_11,TR10CS1
     AG Mobile,Status,Status,Status
    
    在原始PDF中,它是这样的:

    $ cat ~/bin/tabulaextr
    
     #!/bin/bash
     cd ${HOME}/svn-stuff/git.tabula-extractor/bin
     ./tabula $@
    
    $ head DAC06E7D1302B790429AF6E84696FCFAB20B.csv 
    
     Retail Branding,Marketing Name,Device,Model
     "","",AD681H,Smartfren Andromax AD681H
     "","",FJL21,FJL21
     "","",Luno,Luno
     "","",T31,Panasonic T31
     "","",hws7721g,MediaPad 7 Youth 2
     3Q,OC1020A,OC1020A,OC1020A
     7Eleven,IN265,IN265,IN265
     A.O.I. ELECTRONICS FACTORY,A.O.I.,TR10CS1_11,TR10CS1
     AG Mobile,Status,Status,Status
    

    它甚至在最后一页293上写了这些行,对吗

     nabi,"nabi Big Tab HD\xe2\x84\xa2 20""",DMTAB-NV20A,DMTAB-NV20A
     nabi,"nabi Big Tab HD\xe2\x84\xa2 24""",DMTAB-NV24A,DMTAB-NV24A
    
    在PDF页面上的外观如下所示:

    $ cat ~/bin/tabulaextr
    
     #!/bin/bash
     cd ${HOME}/svn-stuff/git.tabula-extractor/bin
     ./tabula $@
    
    $ head DAC06E7D1302B790429AF6E84696FCFAB20B.csv 
    
     Retail Branding,Marketing Name,Device,Model
     "","",AD681H,Smartfren Andromax AD681H
     "","",FJL21,FJL21
     "","",Luno,Luno
     "","",T31,Panasonic T31
     "","",hws7721g,MediaPad 7 Youth 2
     3Q,OC1020A,OC1020A,OC1020A
     7Eleven,IN265,IN265,IN265
     A.O.I. ELECTRONICS FACTORY,A.O.I.,TR10CS1_11,TR10CS1
     AG Mobile,Status,Status,Status
    

    tablaPDF和tablaextractor对于这样的工作来说真的很酷


    更新 这是一个ASCiinema屏幕广播(您也可以通过
    ASCiinema
    命令行工具在Linux/MacOSX/Unix终端上本地重新播放),由
    tabla extractor
    主演:

    As是
    表格提取器的新版本,处于活动状态。1.0.0于2017年7月21日发布

    使用最新的java:

    java -jar ./tabula-1.0.0-jar-with-dependencies.jar \
        --pages=all \
        ./DAC06E7D1302B790429AF6E84696FCFAB20B.pdf
        > support_devices.csv
    

    这可以通过如下所示的IntelliGet()脚本轻松完成

    userVariables = brand, name, device, model;
    { start = Not(Or(Or(IsSubstring("Supported Devices",Line(0)),
                      IsSubstring("Retail Branding",Line(0))),
                    IsEqual(Length(Trim(Line(0))),0))); 
      brand = Trim(Substring(Line(0),10,44));
      name = Trim(Substring(Line(0),45,79));
      device = Trim(Substring(Line(0),80,114));
      model = Trim(Substring(Line(0),115,200));
      output = Concat(brand, ",", name, ",", device, ",", model);
    }
    

    对于希望从PDF中提取表格数据的情况(对于员工必须签署的时间表合同),以下解决方案将更简洁:

  • 使用字段ID创建PDF表单

  • 让人们填写和保存PDF表单

  • 使用一个开源工具,它允许从PDF中提取表单数据。它包括一个命令行示例工具,您可以按如下方式调用该工具以打印所需的字段信息:

    org.apache.pdfbox.examples.interactive.form.PrintFields file.pdf
    
    有关其他选项,请参见


  • 作为上述工作流程的替代方案,您也可以使用数字签名web服务,该服务允许填写PDF表单并将数据导出到表中。例如,它允许和以后。(不是附属的,只是我自己发现的。)

    pdftotext-layout DAC06E7D1302B790429AF6E84696FCFAB20B.pdf-| grep-vE'(支持的设备)^$'|……
    如果它这么简单,@dwarring!-)这个工具对我很有用,前20页是免费的:新的基于Java的tabla版本可以在这里找到:Kurt Pfeifle:你是如何基于-bbox命令测量x和y坐标的?我在pdf viever中测量,得到X和Y,50和100respectively@riccs_0x:pdftotext
    命令需要PostScript点作为距离单位。您的PDF查看器(哪一个?!)是否显示PostScript点?我不记得我是如何准确地确定上述命令的参数的。那是三年多以前的事了。如果我今天必须再次这样做,我会使用Ghostscript和
    'gs-sDEVICE=bbox'
    来确定整个页面的边界框,然后猜测每个列的相应参数,然后根据最初的结果对其进行微调/修改……我使用evice和AtrilSorry来解决这个问题,我知道这个问题是很久以前的事了。我曾经多次遇到过这个问题,我已经设法解决了它,但我正在寻找一种更稳定的方法。谢谢你在这里提出的好主意。