Как извлечь текст и сохранить как файл excel с помощью python или JavaScript

Как извлечь текст из этих PDF-файлов, где некоторые данные представлены в виде таблицы, а некоторые — на основе ключевых значений

например: https://drive.internxt.com/s/file/78f2d73478b832b2ab55/3edb275967deeca6ad33e7d53f2337c50d5dfb50e0aa525bb7f10d49dff1e2b4

Это то, что я пробовал:

import PyPDF2
import openpyxl

from openpyxl import Workbook

pdfFileObj = open('sample.pdf', 'rb')
pdfReader = PyPDF2.PdfFileReader(pdfFileObj)
pdfReader.numPages

pageObj = pdfReader.getPage(0)
mytext = pageObj.extractText()


wb = Workbook()
sheet = wb.active
sheet.title = 'MyPDF'
sheet['A1'] = mytext

wb.save('sample.xlsx')
print('Save')

Однако я бы хотел, чтобы данные хранились в следующем формате.

Как извлечь текст и сохранить как файл excel с помощью python или JavaScript

🤔 А знаете ли вы, что...
С Python можно создавать ботов для социальных сетей и мессенджеров.


333
1

Ответ:

Решено

Этот PDF-файл не имеет четко определенных таблиц, поэтому не может использовать какой-либо инструмент для извлечения всех данных в одном формате таблицы. Что мы можем сделать, так это прочитать весь pdf как текст. И обработайте каждое поле данных построчно, используя регулярное выражение для извлечения данных.

Прежде чем двигаться дальше, установите пакет pdfplumber для Python.

pip install pdfplumber

Предположения

Вот некоторые предположения, которые я сделал для вашего pdf, и соответственно я написал код.

  1. Первая строка всегда будет содержать заголовок Account History Report.
  2. Вторая строка будет содержать имена IMAGE All Notes
  3. Третья строка будет содержать только данные Date Created в виде ключ:значение.
  4. Четвертая строка будет содержать только данные Number of Pages в виде ключ:значение.
  5. Пятая строка будет содержать только данные Client Code, Client Name
  6. Начиная со строки 6, PDF-файл может иметь несколько объектов данных, таких объектов данных, например, в этом PDF-файле, равно 2, но может быть любое количество объектов.
  7. Каждый объект данных будет содержать следующие поля:
  8. Первая строка в объекте данных будет содержать только данные Our Ref, Name, Ref 1, Ref 2
  9. Строка второй строки будет содержать данные только в том виде, в котором они представлены в формате pdf Amount, Total Paid, Balance, Date of A/C, Date Received
  10. Третья строка в объекте данных будет содержать данные Last Paid, Amt Last Paid, Status, Collector.
  11. Четвертая строка будет содержать название столбца Date Notes
  12. Последующие строки будут содержать данные в виде таблицы, пока не будет запущен следующий объект данных.
  13. Я также предполагаю, что каждый объект данных будет содержать первые данные с ключом Our Ref :.
  14. Я предполагаю, что объект данных будет разделен в первой строке каждого объекта в шаблоне ключевых значений как Our Ref :Value Name: Value Ref 1 :Value Ref 2:value
pattern = r'Our Ref.*?Name.*?Ref 1.*?Ref 2.*?'
  1. Обратите внимание, что прямоугольник, который я создал (жирный черный) на изображении выше, я называю как объект данных.

  2. Окончательные данные будут храниться в словаре (json), где объект данных будет иметь ключ как dataentity1, dataentity2, dataentity3 в зависимости от количества объектов, которые у вас есть в вашем PDF-файле.

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

КОД

Вот простой элегантный код, который дает вам информацию из pdf в виде json. В выводе первые несколько полей содержат информацию из части заголовка, последующие объекты данных можно найти как data_entity 1 и 2.

В приведенном ниже коде все, что вам нужно изменить, это pdf_path.

import pdfplumber
import re

# regex pattern for keys in line1 of data entity
my_regex_dict_line1 = {
    'Our Ref' : r'Our Ref :(.*?)Name',
    'Name' : r'Name:(.*?)Ref 1',
    'Ref 1' : r'Ref 1 :(.*?)Ref 2',
    'Ref 2' : r'Ref 2:(.*?)$'
}

# regex pattern for keys in line2 of data entity
my_regex_dict_line2 = {
    'Amount' : r'Amount:(.*?)Total Paid',
    'Total Paid' : r'Total Paid:(.*?)Balance',
    'Balance' : r'Balance:(.*?)Date of A/C',
    'Date of A/C' : r'Date of A/C:(.*?)Date Received',
    'Date Received' : r'Date Received:(.*?)$'
}

# regex pattern for keys in line3 of data entity
my_regex_dict_line3  = {
    'Last Paid' : r'Last Paid:(.*?)Amt Last Paid',
    'Amt Last Paid' : r'Amt Last Paid:(.*?)A/C\s+Status',
    'A/C Status': r'A/C\s+Status:(.*?)Collector',
    'Collector' : r'Collector :(.*?)$'
}

def preprocess_data(data):
    return [el.strip() for el in data.splitlines() if el.strip()]
    
def get_header_data(text, json_data = {}):
    header_data_list = preprocess_data(text)
    # third line in text of header contains Date Created field
    json_data['Date Created'] = re.search(r'Date Created:(.*?)$', header_data_list[2]).group(1).strip()
    # fourth line in text contains Number of Pages, Client Code, Client Name
    json_data['Number of Pages'] = re.search(r'Number of Pages:(.*?)$', header_data_list[3]).group(1).strip()
    # fifth line in text contains Client Code and ClientName
    json_data['Client Code'] = re.search(r'Client Code - (.*?)Client Name', header_data_list[4]).group(1).strip()
    json_data['ClientName'] = re.search(r'Client Name - (.*?)$', header_data_list[4]).group(1).strip()
    
def iterate_through_regex_and_populate_dictionaries(data_dict, regex_dict, text):
    ''' For the given pattern of regex_dict, this function iterates through each regex pattern and adds the key value to regex_dict dictionary '''
    for key, regex in regex_dict.items():
            matched_value = re.search(regex, text)
            if matched_value is not None:
                data_dict[key] = matched_value.group(1).strip()

def populate_date_notes(data_dict, text):
    ''' This function populates date and Notes in the data chunk in the form of list to data_dict dictionary '''
    data_dict['Date'] = []
    data_dict['Notes'] = []
    iter = 4
    while(iter < len(text)):
        date_match = re.search(r'(\d{2}/\d{2}/\d{4})',text[iter])
        data_dict['Date'].append(date_match.group(1).strip())
        notes_match = re.search(r'\d{2}/\d{2}/\d{4}\s*(.*?)$',text[iter])
        data_dict['Notes'].append(notes_match.group(1).strip())
        iter += 1   

data_index = 1
json_data = {}
pdf_path = r'C:\Users\hpoddar\Desktop\Temp\sample3.pdf' # ENTER YOUR PDF PATH HERE
pdf_text = ''
data_entity_sep_pattern = r'(?=Our Ref.*?Name.*?Ref 1.*?Ref 2)'

if (__name__ == '__main__'):
    with pdfplumber.open(pdf_path) as pdf:
        index = 0
        while(index < len(pdf.pages)):
            page = pdf.pages[index]
            pdf_text += '\n' + page.extract_text()
            index += 1
            
    split_on_data_entity = re.split(data_entity_sep_pattern, pdf_text.strip())
    # first data in the split_on_data_entity list will contain the header information
    get_header_data(split_on_data_entity[0], json_data)
    while(data_index < len(split_on_data_entity)):
        data_entity = {}
        data_processed = preprocess_data(split_on_data_entity[data_index])
        iterate_through_regex_and_populate_dictionaries(data_entity, my_regex_dict_line1, data_processed[0])
        iterate_through_regex_and_populate_dictionaries(data_entity, my_regex_dict_line2, data_processed[1])
        iterate_through_regex_and_populate_dictionaries(data_entity, my_regex_dict_line3, data_processed[2])
        if (len(data_processed) > 3 and data_processed[3] != None and 'Date' in data_processed[3] and 'Notes' in data_processed[3]):
            populate_date_notes(data_entity, data_processed)
            json_data['data_entity' + str(data_index)] = data_entity
        data_index += 1
            
    print(json_data)

Выход :

Строка результата:

{'Date Created': '18/04/2022', 'Number of Pages': '4', 'Client Code': '110203', 'ClientName': 'AWS PTE. LTD.', 'data_entity1': {'Our Ref': '2118881115', 'Name': 'Sky Blue', 'Ref 1': '12-34-56789-2021/2', 'Ref 2': 'F2021004444', 'Amount': '$100.11', 'Total Paid': '$0.00', 'Balance': '$100.11', 'Date of A/C': '01/08/2021', 'Date Received': '10/12/2021', 'Last Paid': '', 'Amt Last Paid': '', 'A/C Status': 'CLOSED', 'Collector': 'Sunny Jane', 'Date': ['04/03/2022'], 'Notes': ['Letter Dated 04 Mar 2022.']}, 'data_entity2': {'Our Ref': '2112221119', 'Name': 'Green Field', 'Ref 1': '98-76-54321-2021/1', 'Ref 2': 'F2021001111', 'Amount': '$233.88', 'Total Paid': '$0.00', 'Balance': '$233.88', 'Date of A/C': '01/08/2021', 'Date Received': '10/12/2021', 'Last Paid': '', 'Amt Last Paid': '', 'A/C Status': 'CURRENT', 'Collector': 'Sam Jason', 'Date': ['11/03/2022', '11/03/2022', '08/03/2022', '08/03/2022', '21/02/2022', '18/02/2022', '18/02/2022'], 'Notes': ['Email for payment', 'Case Status', 'to send a Letter', '845***Ringing, No reply', 'Letter printed - LET: LETTER 2', 'Letter sent - LET: LETTER 2', '845***Line busy']}}

Теперь, когда вы получили данные в формате json, вы можете загрузить их в файл csv, в виде фрейма данных или в любом другом формате, в котором вам нужны данные.

Сохранить как xlsx

Чтобы сохранить то же самое в файле xlsx в формате, показанном на изображении в вопросе выше. Мы можем использовать модуль записи xlsx, чтобы сделать то же самое. Пожалуйста, установите пакет, используя pip

pip install xlsxwriter

Из предыдущего кода у нас есть все наши данные в переменной json_data, мы будем перебирать все объекты данных и записывать данные в соответствующую ячейку, указанную row, col в коде.

import xlsxwriter
workbook = xlsxwriter.Workbook('Sample.xlsx')
worksheet = workbook.add_worksheet("Sheet 1")
row = 0
col = 0

# write columns
columns = ['Account History Report', 'All Notes'] + [ key for key in json_data.keys() if 'data_entity' not in key ] + list(json_data['data_entity1'].keys())
worksheet.write_row(row, col,  tuple(columns))
row += 1

column_index_map = {}
for index, col in enumerate(columns):
    column_index_map[col] =  index

# write the header
worksheet.write(row, column_index_map['Date Created'],  json_data['Date Created'])
worksheet.write(row, column_index_map['Number of Pages'],  json_data['Number of Pages'])
worksheet.write(row, column_index_map['Client Code'],  json_data['Client Code'])
worksheet.write(row, column_index_map['ClientName'],  json_data['ClientName'])
data_entity_index = 1


#iterate through each data entity and for each key insert the values in the sheet
while True:
    data_entity_key = 'data_entity' + str(data_entity_index)
    row_size = 1
    if (json_data.get(data_entity_key) != None):
        for key, value in json_data.get(data_entity_key).items():
            if (type(value) == list):
                worksheet.write_column(row, column_index_map[key],  tuple(value))
                row_size = len(value)
            else:
                worksheet.write(row, column_index_map[key], value)
    else:
        break
    data_entity_index += 1
    row += row_size
    
workbook.close()

Результат : Приведенный выше код создает файл sample.xlsx в рабочем каталоге.