Как преобразовать файл PDF в файл CSV с помощью Python Pandas

У меня есть файл PDF, мне нужно преобразовать его в файл CSV, это мой пример файла PDF в качестве ссылки https://online.flippingbook.com/view/352975479/ используемый код

import re
import parse
import pdfplumber
import pandas as pd
from collections import namedtuple
file = "Battery Voltage.pdf"
lines = []
total_check = 0

with pdfplumber.open(file) as pdf:
    pages = pdf.pages
    for page in pdf.pages:
        text = page.extract_text()
        for line in text.split('\n'):
            print(line)

с приведенным выше сценарием я не получаю надлежащего вывода, столбец «Время» «AM» появляется в следующей строке. Вывод, который я получаю, такой

Файлы PDF не содержат информации о том, как должен располагаться текст. Все, что у него есть, это положение текста на странице. Для такого инструмента, как pdfplumber, все, что он может сделать, это угадать, в каком порядке он должен идти, глядя на координаты X и Y текста на странице.

Nick ODell 26.11.2022 05:28

В этом конкретном случае выходные данные имеют шаблон, поэтому вы можете исправить это, найдя строки с содержимым «AM» или «PM» и добавив их в конец третьего поля предыдущей строки после разделения на пробел.

Nick ODell 26.11.2022 05:29
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
2
1 112
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Для таких случаев создайте анализатор, который преобразует непригодные данные во что-то, что вы можете использовать.

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

Обратите внимание, что для этого конкретного файла вы можете игнорировать AM/PM, поскольку время указано в 24-часовом формате.

import pdfplumber


file = "Battery Voltage.pdf"
skiplines = [
    "Battery Voltage",
    "AM",
    "PM",
    "Sr No DateTIme Voltage (v) Ignition",
    ""
]


with open("output.csv", "w") as outfile:
    header = "serialnumber;date;time;voltage;ignition\n"
    outfile.write(header)
    with pdfplumber.open(file) as pdf:
        for page in pdf.pages:
            for line in page.extract_text().split('\n'):
                if line.strip() in skiplines:
                    continue
                outfile.write(";".join(line.split())+"\n")

РЕДАКТИРОВАТЬ

Итак, файлы JSON в python — это просто список элементов dict (да, это упрощение).

Единственное, что вам нужно изменить, это то, как вы на самом деле обрабатываете линии. Суть логики не меняется...

import pdfplumber
import json


file = "Battery Voltage.pdf"
skiplines = [
    "Battery Voltage",
    "AM",
    "PM",
    "Sr No DateTIme Voltage (v) Ignition",
    ""
]
result = []


with pdfplumber.open(file) as pdf:
    for page in pdf.pages:
        for line in page.extract_text().split("\n"):
            if line.strip() in skiplines:
                continue
            serialnumber, date, time, voltage, ignition = line.split()
            result.append(
                {
                    "serialnumber": serialnumber,
                    "date": date,
                    "time": time,
                    "voltage": voltage,
                    "ignition": ignition,
                }
            )

with open("output.json", "w") as outfile:
    json.dump(result, outfile)

Это может помочь вам увидеть, как поверхность PDF-файла отображается на экране. так что одна строка обычного текста размещается на дисплее по частям. (Здесь я подчеркиваю, где должен быть размещен первый AM.

В качестве побочного вопроса я думаю, что первый AM в файле на первый взгляд закодирован как этот блок.

BT
/F1 12 Tf
1 0 0 1 224.20265 754.6322 Tm
[<001D001E>] TJ
ET

Где в этой области 1D = A и 1E = M

Итак, если вы хотите извлечь каждую СТРОКУ в том виде, в каком она отображается, самый простой способ — использовать библиотеку, такую ​​как pdftotext, которая специально выводит каждую строку текста так, как она отображается на странице.

Таким образом, используя такую ​​атаку, как табличное разделение запятыми, вы можете ожидать, что каждому AM будет предоставлена ​​​​своя строка. Что по логике должно быть " ",AM," "," ", но некоторые экстракторы должны говорить nan, AM, nan, nan

Как текст это выглядит так из одной программируемой строки

pdftotext -layout "Battery Voltage.pdf"

Это выведет «Battery Voltage.txt» в той же рабочей папке.

Затем размещение этого в электронной таблице становится

Теперь мы можем экспортировать в пару кликов (больше не будет) как «правильный вывод» csv вместе со всеми его странностями, которые влечет за собой csv.

,,Battery Vo,ltage,




Sr No,DateT,Ime,Voltage (v),Ignition
1,01/11/2022,00:08:10,47.15,Off
,AM,,,
2,01/11/2022,00:23:10,47.15,Off
,AM,,,
3,01/11/2022,00:38:10,47.15,Off
,AM,,,
4,01/11/2022,00:58:10,47.15,Off
,AM,,,
5,01/11/2022,01:18:10,47.15,Off
,AM,,,
6,01/11/2022,01:33:10,47.15,Off
,AM,,,
7,01/11/2022,01:48:10,47.15,Off
,AM,,,
8,01/11/2022,02:03:10,47.15,Off
,AM,,,
9,01/11/2022,02:18:10,47.15,Off
,AM,,,
10,01/11/2022,02:37:12,47.15,Off
,AM,,,

Итак, если правки не были внесены до создания csv, проще опубликовать процесс в редакторе, например, на этой html-странице (нет необходимости в дополнительных приложениях).

,,Battery,Voltage,
Sr No,Date,Time,Voltage (v),Ignition
1,01/11/2022,00:08:10,47.15,Off,AM,,,
2,01/11/2022,00:23:10,47.15,Off,AM,,,
3,01/11/2022,00:38:10,47.15,Off,AM,,,
4,01/11/2022,00:58:10,47.15,Off,AM,,,
5,01/11/2022,01:18:10,47.15,Off,AM,,,
6,01/11/2022,01:33:10,47.15,Off,AM,,,
7,01/11/2022,01:48:10,47.15,Off,AM,,,
8,01/11/2022,02:03:10,47.15,Off,AM,,,
9,01/11/2022,02:18:10,47.15,Off,AM,,,
10,01/11/2022,02:37:12,47.15,Off,AM,,,

Затем при повторном импорте он выглядит более человеческим

В обсуждениях было подтверждено, что все, что нужно, это средство для структурированного списка и первого анализа с использованием
pdftotext -layout -nopgbrk -x 0 -y 60 -W 800 -H 800 -fixed 6 "Battery Voltage.pdf" &type "battery voltage.txt"|findstr "O">battery.txt

будет выводить регулируемые столбцы данных для кадрирования с фиксированным заголовком или разделением или иным образом с использованием очищенных данных.

                 1            01-11-2022 00:08:10         47.15                 Off
                 2            01-11-2022 00:23:10         47.15                 Off
                 3            01-11-2022 00:38:10         47.15                 Off
                 4            01-11-2022 00:58:10         47.15                 Off
                 5            01-11-2022 01:18:10         47.15                 Off
...
               32357          24-11-2022 17:48:43         45.40                  On
               32358          24-11-2022 17:48:52         44.51                  On
               32359          24-11-2022 17:48:55         44.51                  On
               32360          24-11-2022 17:48:58         44.51                  On
               32361          24-11-2022 17:48:58         44.51                  On

На этом этапе мы можем использовать обработку текста, такую ​​​​как csv, или добавить скобки json.

for /f "tokens=1,2,3,4,5 delims= " %%a In ('Findstr /C:"O" battery.txt') do echo csv is "%%a,%%b,%%c,%%d,%%e">output.txt
...
csv is "32357,24-11-2022,17:48:43,45.40,On"
csv is "32358,24-11-2022,17:48:52,44.51,On"
csv is "32359,24-11-2022,17:48:55,44.51,On"
csv is "32360,24-11-2022,17:48:58,44.51,On"
csv is "32361,24-11-2022,17:48:58,44.51,On"

Итак, запрос для JSON (не моя сильная сторона, поэтому вам может потребоваться улучшить мой код, поскольку я не знаю, чего ожидает монго)

вот скидываю pdf на аккум.бат

{"line_id":1,"created":{"date":"01-11-2022"},{"time":"00:08:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":2,"created":{"date":"01-11-2022"},{"time":"00:23:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":3,"created":{"date":"01-11-2022"},{"time":"00:38:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":4,"created":{"date":"01-11-2022"},{"time":"00:58:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":5,"created":{"date":"01-11-2022"},{"time":"01:18:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":6,"created":{"date":"01-11-2022"},{"time":"01:33:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":7,"created":{"date":"01-11-2022"},{"time":"01:48:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":8,"created":{"date":"01-11-2022"},{"time":"02:03:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":9,"created":{"date":"01-11-2022"},{"time":"02:18:10"},{"Voltage":"47.15"},{"State","Off"}}
{"line_id":10,"created":{"date":"01-11-2022"},{"time":"02:37:12"},{"Voltage":"47.15"},{"State","Off"}}

это немного медленнее, чем в чистой консоли, поэтому давайте запустим его вслепую, добавив @, это все равно займет время, так как мы работаем с обычным текстом, поэтому ожидайте значительную задержку для 32 000+ строк = 2 + 1/2 минуты на мой комплект

pdftotext -layout -nopgbrk -x 0 -y 60 -W 700 -H 800 -fixed 8 "%~1" battery.txt

echo Heading however you wish it for json perhaps just opener [ but note only one redirect chevron >"%~dpn1.txt"

for /f "tokens=1,2,3,4,5 delims= " %%a In ('Findstr /C:"O" battery.txt') do @echo  "%%a": { "Date": "%%b", "Time": "%%c", "Voltage": %%d, "Ignition": "%%e" },>>"%~dpn1.txt"
REM another json style could be  { "Line_Id": %%a, "Date": "%%b", "Time": "%%c", "Voltage": %%d, "Ignition": "%%e" },
REM another for an array can simply be [%%a,"%%b","%%c",%%d,"%%e" ],

echo Tailing however you wish it for json perhaps just final closer ] but note double chevron >>"%~dpn1.txt"

Чтобы увидеть прогресс, измените @echo { на @echo %%a&echo {

Таким образом, через минуту или около того однако это, как правило, добавляет лишнюю минуту для всей этой активности на дисплее! до того, как окно закроется в знак завершения.

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