Извлечение текста из файлов PDF в 1С

07.08.24

Разработка - Инструментарий разработчика

В данной статье я расскажу, как извлечь текст из документа в формате PDF для его дальнейшей обработки в 1С.

Подготовка скрипта на Python

Для решения задачи извлечения текста из PDF файла был использован движок распознавания Google Tesseract OCR. Ссылка на статью, которой я руководствовался при написании скрипта на python: Извлечение текста из файлов PDF при помощи Python. Повторяться не буду, так как она довольно подробная и понятная.

Итоговый код, получившийся на python:

import PyPDF2
from pdfminer.high_level import extract_pages, extract_text
from pdfminer.layout import LTTextContainer, LTChar, LTRect, LTFigure, LTImage
from PIL import Image
import pdfplumber
from pdf2image import convert_from_path
import pytesseract
import os
import argparse

pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe'

def text_extraction(element):
    line_text=element.get_text()

    line_format = []
    for text_line in element:
        if isinstance(text_line, LTTextContainer):
            for character in text_line:
                if isinstance(character, LTChar):
                    line_format.append(character.fontname)
                    line_format.append(character.size)
    format_per_line = list(set(line_format))
    return (line_text, format_per_line)

def crop_image(element, pageIMAGE):
    [list_x0,list_y0,list_x1,list_y1]=[element.x0,element.y0,element.x1,element.y1]
    pageIMAGE.mediabox.lower_left=(list_x1,list_y0)
    pageIMAGE.mediabox.right=(list_x0,list_y1)

    cropped_pdf_writer=PyPDF2.PdfWriter()
    cropped_pdf_writer.add_page(pageIMAGE)

    with open('cropped_image.pdf','wb') as cropped_pdf_file:
        cropped_pdf_writer.write(cropped_pdf_file)

def convert_to_Image(input_file,):
    images=convert_from_path(input_file, poppler_path=r'poppler-24.07.0\Library\bin')

    image=images[0]

    output_file="PDF_Image.png"
    image.save(output_file, format='PNG')

def image_to_text(image_path):
    image=Image.open(image_path)

    text=pytesseract.image_to_string(image)

    return text

def extract_table(pdf,page_number,table_number):
    pdf=pdfplumber.open(pdf)

    table_page=pdf.pages[page_number]
    table=table_page.extract_tables()[table_number]
    return table

def table_converter(table):
    table_string = ''
    # Итеративно обходим каждую строку в таблице
    for row_num in range(len(table)):
        row = table[row_num]
        # Удаляем разрыв строки из текста с переносом
        cleaned_row = [item.replace('\n', ' ') if item is not None and '\n' in item else 'None' if item is None else item for item in row]
        # Преобразуем таблицу в строку
        table_string+=('|'+'|'.join(cleaned_row)+'|'+'\n')
    # Удаляем последний разрыв строки
    table_string = table_string[:-1]
    return table_string

def main():
    parser = argparse.ArgumentParser(description="Конвертация pdf УПД в Excel")
    parser.add_argument("input_file", type = str, help = "Путь к входному файлу")

    args = parser.parse_args()

    #pdf_path = ('upd2.pdf')
    pdf_path = (args.input_file)
    pdfFile = open(pdf_path, 'rb')

    pdfReader = PyPDF2.PdfReader(pdfFile)

    text_per_page = {}

    for pagenum, page in enumerate(extract_pages(pdf_path)):

        pageIMAGE = pdfReader.pages[pagenum]
        page_text = []
        line_format = []
        text_from_Image = []
        text_from_Table = []
        page_content = []

        table_number = 0

        first_element = True
        table_extraction_flag = False

        pdf = pdfplumber.open(pdf_path)
        page_tables = pdf.pages[pagenum]
        tables = page_tables.find_tables()

        page_elements = [(element.y1, element) for element in page._objs]
        page_elements.sort(key=lambda a: a[0], reverse=True)

        for i, component in enumerate(page_elements):
            pos = component[0]
            element = component[1]

            if isinstance(element, LTTextContainer):

                if (table_extraction_flag == False):
                    (line_text, format_per_line) = text_extraction(element)
                    page_text.append(line_text)
                    line_format.append(format_per_line)
                    page_content.append(line_text)


                else:
                    pass

            if isinstance(element, LTFigure):
                crop_image(element, pageIMAGE)
                # Преобразуем обрезанный pdf в изображение
                convert_to_Image('cropped_image.pdf')
                # Извлекаем текст из изображения
                image_text = image_to_text('PDF_image.png')
                text_from_Image.append(image_text)
                page_content.append(image_text)
                # Добавляем условное обозначение в списки текста и формата
                page_text.append('image')
                line_format.append('image')

            if isinstance(element, LTRect):

                if (first_element == True and (table_number + 1) <= len(tables)):
                    lower_side = page.bbox[3] - tables[table_number].bbox[3]
                    upper_side = element.y1

                    table = extract_table(pdfFile, pagenum, table_number)

                    table_string = table_converter(table)

                    text_from_Table.append(table_string)
                    page_content.append(table_string)

                    table_element = False

                    page_text.append('table')
                    line_format.append('table')

                if (element.y0 >= lower_side) and (element.y1 <= upper_side):

                    pass

                elif not isinstance(page_elements[i + 1][1], LTRect):

                    table_extraction_flag = False

                    first_element = True

                    table_number += 1

        dctkey = 'Page_' + str(pagenum)
        text_per_page[dctkey] = [page_text, line_format, text_from_Image, text_from_Table, page_content]

    pdfFile.close()

    if os.path.exists('cropped_image.pdf'):
        os.remove('cropped_image.pdf')

    if os.path.exists('PDF_image.png'):
        os.remove('PDF_image.png')

    result = ''.join(text_per_page['Page_0'][4])
    file = open("test.txt", "w")
    file.write(result)
    file.close()

if __name__ == "__main__":
    main()


Выделю следующие строки:

import argparse

Здесь я импортирую модуль argparse, который предназначен для работы с аргументами командной строки.
 

parser = argparse.ArgumentParser(description="Конвертация pdf УПД в Excel")
parser.add_argument("input_file", type = str, help = "Путь к входному файлу")
args = parser.parse_args()
pdf_path = (args.input_file)

Здесь я инициализирую аргумент "Путь к входному файлу" и прокидываю его в качестве пути к pdf файлу.

Результат работы скрипта является строкой. Эту строку я записываю в обычный текстовый файл.

После написания скрипта на python необходимо скомпилировать скрип в exe файл.

Для этого необходимо установить pyinstaller.

Прописываем в командной строке

pip install pyinstaller
cd путь/к/вашему/скрипту
pyinstaller --onefile script.py

Параметр --onefile указывает PyInstaller упаковать все файлы в один исполняемый файл.

После выполнения команды PyInstaller, в директории вашего проекта появятся несколько новых папок и файлов:

build – временная папка для файлов сборки.

dist – папка, в которой находится ваш .exe файл.

.spec файл – спецификация сборки, которую можно использовать для дальнейших настроек.

Перейдите в папку dist и найдите там файл script.exe. Это и есть ваш исполняемый файл.
 

Интеграция с 1С

	ТабличныйДокумент = Новый ТабличныйДокумент;
	
	Путь = СтрЗаменить(ПутьКPDFФайлу, "\", "\\");    
	МассивПапок = СтрРазделить(ПутьКИсполняемомуФайлу, "\", Ложь);  
	ПутьКТекстовомуФайлу = ""; 
	
	Для Счетчик = 0 По МассивПапок.Количество() - 2 Цикл
		
		  ПутьКТекстовомуФайлу = ПутьКТекстовомуФайлу + МассивПапок[Счетчик] + "\";
		
	КонецЦикла;
	
	КомандаСистемы("main.exe " + Путь, ПутьКТекстовомуФайлу); 
	
	Сек = 5;
	КонДата = ТекущаяДата() + сек;
	Пока ТекущаяДата() < КонДата Цикл
		// ждемссс....
	КонецЦикла; 
	
	ТекстовыйФайл = Новый ТекстовыйДокумент;
		
	ТекстовыйФайл.Прочитать(ПутьКТекстовомуФайлу + "test.txt",
	КодировкаТекста.Системная, 
	Символы.ПС
	);
	
	ТекстФайла = ТекстовыйФайл.ПолучитьТекст(); 
	КонвертироватьНаСервере(ТабличныйДокумент, ТекстФайла); 
	
	ТабличныйДокумент.Записать(ПутьКExcelФайлу, ТипФайлаТабличногоДокумента.XLSX);  
	ЗапуститьПриложение(ПутьКExcelФайлу);

Теперь этот скрипт необходимо запустить из 1С.

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

Скрипт запускает следующая строка:

КомандаСистемы("main.exe " + Путь, ПутьКТекстовомуФайлу); 

Она принимает в качестве первого аргумента имя exe-файла вместе с аргументами (в нашем случае это путь к pdf файлу), а в качестве второго аргумента - каталог, в котором находится exe.

Переменные ПутьКPDFФайлу и ПутьКИсполняемомуФайлу задаются на форме.

При этом в пути к pdf файлу необходимо экранировать символ "\", поэтому заменяем его на "\\".

Далее ждём 5 секунд, чтобы исполняемый файл точно успел выполнить свою функцию и производим считывание текстового файла.

Сам текстовый файл уже парсим как душе угодно через СтрРазделить() или СтрНайти().

В моем примере я считывал документ УПД и вот, что я получил на выходе:

И разделив его следующим образом

МассивСтрок = СтрРазделить(ТекстФайла, Символы.ПС, Ложь);

Получил массив, с которым уже вполне можно работать.


Спасибо за внимание! Если остались вопросы - жду в комментариях.

Обработка PDF python парсинг.

См. также

SALE! 15%

Инструментарий разработчика Роли и права Запросы СКД Программист Платформа 1С v8.3 Управляемые формы Запросы Система компоновки данных Конфигурации 1cv8 Платные (руб)

Набор инструментов программиста и специалиста 1С для всех конфигураций на управляемых формах. В состав входят инструменты: Консоль запросов, Консоль СКД, Консоль кода, Редактор объекта, Анализ прав доступа, Метаданные, Поиск ссылок, Сравнение объектов, Все функции, Подписки на события и др. Редактор запросов и кода с раскраской и контекстной подсказкой. Доработанный конструктор запросов тонкого клиента. Продукт хорошо оптимизирован и обладает самым широким функционалом среди всех инструментов, представленных на рынке.

10000 руб.

02.09.2020    160233    882    399    

866

SALE! 15%

Инструментарий разработчика Чистка данных Свертка базы Инструменты администратора БД Системный администратор Программист Руководитель проекта Платформа 1С v8.3 Конфигурации 1cv8 1С:Управление торговлей 10 1С:ERP Управление предприятием 2 1С:Бухгалтерия 3.0 1С:Управление торговлей 11 Россия Платные (руб)

Инструмент представляет собой обработку для проведения свёртки или обрезки баз данных. Работает на ЛЮБЫХ конфигурациях (УТ, БП, ERP и т.д.). Поддерживаются управляемые и обычные формы. Может выполнять свертку сразу нескольких баз данных и выполнять их автоматически без непосредственного участия пользователя.

8400 7140 руб.

20.08.2024    8087    60    28    

70

Инструментарий разработчика Программист Платформа 1С v8.3 Конфигурации 1cv8 Платные (руб)

Инструмент для написания и отладки кода в режиме «1С:Предприятие». Представляет собой консоль кода с возможностью пошаговой отладки, просмотра значений переменных любых типов, использования процедур и функций, просмотра стека вызовов, вычисления произвольных выражений на встроенном языке в контексте точки останова, синтаксического контроля и остановки по ошибке. В консоли используется удобный редактор кода с подсветкой, контекстной подсказкой, возможностью вызова конструкторов запроса и форматной строки.

9360 руб.

17.05.2024    23635    69    45    

117

SALE! 15%

Пакетная печать Печатные формы Инструментарий разработчика Программист Платформа 1С v8.3 Запросы 1С:Зарплата и кадры бюджетного учреждения 1С:Конвертация данных 1С:ERP Управление предприятием 2 1С:Управление торговлей 11 Платные (руб)

Инструмент, позволяющий абсолютно по-новому взглянуть на процесс разработки печатных форм. Благодаря конструктору можно значительно снизить затраты времени на разработку печатных форм, повысить качество и "прозрачность" разработки, а также навести порядок в многообразии корпоративных печатных форм.

22200 19980 руб.

06.10.2023    15507    36    7    

71

SALE! 15%

Инструменты администратора БД Инструментарий разработчика Роли и права Программист Платформа 1С v8.3 Конфигурации 1cv8 Россия Платные (руб)

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

10000 8500 руб.

10.11.2023    10540    37    27    

62

SALE! 35%

Инструментарий разработчика Инструменты администратора БД Системный администратор Программист Платформа 1С v8.3 Управляемые формы Конфигурации 1cv8 Россия Платные (руб)

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

4800 3120 руб.

14.01.2013    188200    1141    0    

912

SALE! 15%

Инструментарий разработчика Программист 8.3.14 1С:Конвертация данных Россия Платные (руб)

Расширение для конфигурации “Конвертация данных 3”. Добавляет подсветку синтаксиса, детальную контекстную подсказку, глобальный поиск по коду.

15000 12750 руб.

07.10.2021    17367    6    32    

42

Инструментарий разработчика Программист Платные (руб)

Менеджер конфигураций 1С — альтернативный стартер информационных баз 1С:Предприятие.

1800 руб.

21.02.2023    7761    8    35    

23
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. VVladislav 07.08.24 15:12 Сейчас в теме
ого, бесплатный скрипт для срипткидди. благодарю.
извините, а Маин.эхе не может вернуть код возврата? посидели бы, подождали.
ну и цикл жрёт ресурсы. если совсем никак по другому, то ожидание через обработчик проще делать, и там уже сравнивать текущее время с целевым.
2. siamagic 08.08.24 02:29 Сейчас в теме
(1) Tcnm ЗапуститьПриложение, ожидание в цикле трешак конечно.
3. siamagic 08.08.24 02:31 Сейчас в теме
pdf2text распознает лучше, в идеале неиронку прикрутить. Думаю таблица у вас не будет парсится - в чем смысл тогда этих движений?
4. user1201514 09.08.24 15:21 Сейчас в теме
(3)
pdf2text
Тоже перепробовал много, но остановился на pdf2text, работает намного быстрее и тем более что работает и с linux.
Оставьте свое сообщение