Извлечение текста из файлов 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 парсинг.

См. также

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

Инструменты для разработчиков 1С 8.3: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

12000 руб.

02.09.2020    171680    960    403    

924

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

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

8400 руб.

20.08.2024    14247    108    46    

108

Инструментарий разработчика Программист Платформа 1С v8.3 1C:Бухгалтерия Платные (руб)

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

9360 руб.

17.05.2024    27239    96    48    

137

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

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

22200 руб.

06.10.2023    17251    43    15    

75

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

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

15000 руб.

10.11.2023    11886    45    27    

67

SALE! %

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

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

4800 3840 руб.

14.01.2013    191149    1152    0    

920

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

Разработка Конструктор автоматизированных рабочих мест "Конструктор АРМ" реализована в виде расширения и является универсальным инструментом для создания АРМ любой сложности в пользовательском режиме.

3600 руб.

27.12.2024    1112    2    0    

5

Инструментарий разработчика Программист Платформа 1С v8.3 1C:Бухгалтерия Россия Платные (руб)

Восстановление партий или взаиморасчетов, расчет зарплаты, пакетное формирование документов или отчетов - теперь все это стало доступнее. * Есть желание повысить скорость работы медленных алгоритмов! Но... * Нет времени думать о реализации многопоточности? * о запуске и остановке потоков? * о поддержании потоков в рабочем состоянии? * о передаче данных в потоки и как получить ответ из потока? * об организации последовательности? Тогда ЭТО - то что надо!!!

5000 руб.

07.02.2018    104111    244    100    

307
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
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.
prog1c_vl; +1 Ответить
Оставьте свое сообщение