Как извлечь данные таблицы из PDF как CSV из командной строки?

Я хочу извлечь все строки отсюда, игнорируя заголовки столбцов, а также заголовки всех страниц, т.е. Supported Devices,

pdftotext -layout DAC06E7D1302B790429AF6E84696FCFAB20B.pdf - \
 | sed '$d'                                                  \
 | sed -r 's/ +/,/g; s/ //g'                                 \
 > output.csv

Полученный файл должен быть в формате электронной таблицы CSV (поля значений, разделенные запятыми).

Другими словами, я хочу улучшить указанную выше команду, чтобы вывод вообще не тормозил. Есть идеи?

7 ответов

Решение

Я предложу вам и другое решение.

Хотя в этом случае pdftotext Метод работает с разумными усилиями, могут быть случаи, когда не каждая страница имеет одинаковую ширину столбца (как показывает ваш довольно мягкий PDF).

Здесь не очень известное, но довольно классное бесплатное и открытое программное обеспечение Tabula-Extractor это лучший выбор.

Я сам использую прямую проверку 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 $@

поскольку ~/bin/ в моем $PATH Я просто бегаю

$ tabulaextr --pages all                                 \
         $(pwd)/DAC06E7D1302B790429AF6E84696FCFAB20B.pdf \
        | tee my.csv

извлечь все таблицы со всех страниц и преобразовать их в один файл CSV.

Первые десять (из 8727) строк CVS выглядят так:

$ 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 выглядит так:

Снимок экрана вверху первой страницы образца PDF

Он даже получил эти строки на последней странице, 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 следующим образом:

последняя страница образца PDF

TabulaPDF и Tabula-Extractor действительно, действительно хороши для таких работ!


Обновить

Вот скринкаст ASCiinema (который вы также можете скачать и воспроизвести локально в терминале Linux/MacOSX/Unix с помощью asciinema инструмент командной строки), в ролях tabula-extractor:

/questions/786634/kakovyi-osnovnyie-razlichiya-mezhdu-programmirovaniem-dlya-windows-xp-i-dlya-vista/786650#786650

Как прокомментировал Мартин Р, tabula-java это новая версия tabula-extractor и активный. 1.0.0 был выпущен 21 июля 2017 года.

Загрузите файл JAR и с последней версией Java:

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

То, что вы хотите, довольно просто, но у вас есть и другая проблема (я не уверен, что вы знаете об этом...).

Во-первых, вы должны добавить -nopgbrk для ("Нет разрывов страниц, пожалуйста!") для вашей команды. Потому что эти надоедливые ^L символы, которые в противном случае появляются в выводе, не должны быть отфильтрованы позже.

Добавление grep -vE '(Supported Devices|^$)' затем отфильтрует все ненужные строки, включая пустые строки или строки только с пробелами:

pdftotext -layout -nopgbrk                           \
   DAC06E7D1302B790429AF6E84696FCFAB20B.pdf -        \
 | grep -vE '(Supported Devices|^$|Marketing Name)'  \
 | gsed '$d'                                         \
 | gsed -r 's# +#,#g'                                \
 | gsed '# ##g'                                      \
 > output2.csv

Тем не менее, ваша другая проблема заключается в следующем:

  1. Некоторые поля таблицы пусты.
  2. Пустые поля появляются с -layout вариант, как ряд символов пробела, иногда даже два в одном ряду.
  3. Тем не менее, текстовые столбцы не разделены одинаково от страницы к странице.
  4. Для этого вы не будете знать от строки к строке, сколько пробелов вы должны рассматривать как "пустое поле CSV" (где вам понадобится дополнительное , разделитель).
  5. Как следствие, ваш текущий код будет показывать только одно, два или три (вместо четырех) поля для некоторых строк, и эти поля окажутся в неправильных столбцах!

Для этого есть обходной путь:

  1. Добавить -x ... -y ... -W ... -H ... параметры для pdftotext обрезать PDF по столбцам.
  2. Затем добавьте столбцы с помощью таких утилит, как 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 между ними, вы должны узнать сами. Или задайте новый вопрос:-)

Это можно легко сделать с помощью скрипта IntelliGet ( http://akribiatech.com/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);
}

Вопрос касается командной строки, но, поскольку я вижу здесь еще один ответ, в котором упоминается использование Excel, стоит упомянуть, что теперь вы можете импортировать PDF-файлы из самого Excel. Это сэкономило мне много времени.

Адаптировано на основе инструкций здесь: https://www.makeuseof.com/easily-extract-table-from-pdf/

  1. Откройте новую таблицу Excel.

  2. Перейдите на вкладку Данные.

  3. В разделе «Получить и преобразовать» нажмите «Получить данные».

  4. В списке выберите «Из файла», а затем выберите «Из PDF» .

После нажатия кнопки «Открыть» в Excel откроется окно навигатора. В этом окне вы увидите различные таблицы, содержащиеся в PDF-файле.

  1. Выберите таблицу, которую вы хотите импортировать.

  2. Нажмите «Загрузить».

Я был удивлен тем, насколько хорошо это работает в Windows, после поиска более технического решения в Ubuntu.

Первый ответ Курта — это хороший общий метод для извлечения столбцов текста, но в тех случаях, когда мы хотим импортировать в eXcel в виде электронной таблицы, мы можем просто импортировать текст как обычный текст.

Вот текстовый вывод Windows

      pdftotext -nopgbrk -layout -fixed 4 -y 40 -H 600 -W 1000 "C:\data\DAC06E7D1302B790429AF6E84696FCFAB20B.pdf" -|find " ">>out.txt

первые несколько строк

                                                                                                        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

В этом случае импорт будет столбчатым, включая нечетные символы кавычек, и при желании его можно будет сохранить в формате CSV.

Существует много хороших «бесплатных» текстов для импортеров CSV, позволяющих анализировать и преобразовывать текст в другие форматы, такие как диаграммы или столбцы. некоторые из них могут управляться из командной строки. Это, возможно, наиболее многофункциональный инструмент для пользователей бесплатных[mium] Windows! используя приведенный выше образец файла.

В случае, когда вы хотите извлечь табличные данные из PDF, которые вы контролируете во время создания (для контрактов расписаний, которые должны подписывать ваши сотрудники), следующее решение будет более чистым:

  1. Создайте форму PDF с идентификаторами полей.

  2. Пусть люди заполняют и сохраняют формы PDF.

  3. Используйте Apache PDFBox, инструмент с открытым исходным кодом, который позволяет извлекать данные формы из PDF. Он включает в себя пример инструмента PrintFields из командной строки, который вы бы вызвали следующим образом, чтобы напечатать информацию о нужном поле:

    org.apache.pdfbox.examples.interactive.form.PrintFields file.pdf
    

    Для других вариантов см. Этот вопрос.

В качестве альтернативы вышеуказанному рабочему процессу, возможно, вы также можете использовать веб-службу цифровой подписи, которая позволяет заполнять формы в формате PDF и экспортировать данные в таблицы. Например, SignRequest, который позволяет создавать шаблоны, а затем экспортировать данные подписанных документов. (Не связан, только что нашел это сам.)

Другие вопросы по тегам