Как эффективно извлечь текст из каталога файлов PDF с помощью OCR?

У меня есть большой каталог с файлами PDF (изображения), как я могу эффективно извлечь текст из всех файлов внутри каталога?. Пока я пытался:

import multiprocessing
import textract

def extract_txt(file_path):
    text = textract.process(file_path, method='tesseract')

p = multiprocessing.Pool(2)
file_path = ['/Users/user/Desktop/sample.pdf']
list(p.map(extract_txt, file_path))

Однако он не работает... это занимает много времени (у меня есть документы с 600 страницами). Кроме того: a) Я не знаю, как эффективно обрабатывать часть преобразования каталога. b) Я хотел бы добавить разделитель страниц, скажем: <start/age = 1> ... page content ... <end/page = 1>, но я не знаю, как это сделать.

Таким образом, как я могу применить функцию extract_txt ко всем элементам каталога, которые заканчиваются на .pdf, и возвращать те же файлы в другом каталоге, но в формате .txt, и добавить разделитель страниц с помощью OCR удаление текста?.

Кроме того, я был заинтересован в использовании документов Google для выполнения этой задачи, можно ли программным образом использовать документы Google для решения вышеупомянутой проблемы с извлечением текста?

UPDATE

Что касается вопроса "Добавление разделителя страниц" (<start/age = 1> ... page content ... <end/page = 1>) после прочтения ответа Роланда Смита, я попытался:

from PyPDF2 import PdfFileWriter, PdfFileReader
import textract


def extract_text(pdf_file):
    inputpdf = PdfFileReader(open(pdf_file, "rb"))
    for i in range(inputpdf.numPages):
        w = PdfFileWriter()
        w.addPage(inputpdf.getPage(i))
        outfname = 'page{:03d}.pdf'.format(i)
        with open(outfname, 'wb') as outfile:  # I presume you need `wb`.
             w.write(outfile)
        print('\n<begin page pos =' , i, '>\n')
        text = textract.process(str(outfname), method='tesseract')
        os.remove(outfname)  # clean up.
        print(str(text, 'utf8'))
        print('\n<end page pos =' , i, '>\n')

extract_text('/Users/user/Downloads/ImageOnly.pdf')

Однако у меня все еще есть проблемы с частью print(), так как вместо печати было бы более полезно сохранить в файл весь вывод. Таким образом, я попытался перенаправить вывод в файл:

sys.stdout=open("test.txt","w")
print('\n<begin page pos =' , i, '>\n')
sys.stdout.close()
text = textract.process(str(outfname), method='tesseract')
os.remove(outfname)  # clean up.
sys.stdout=open("test.txt","w")
print(str(text, 'utf8'))
sys.stdout.close()
sys.stdout=open("test.txt","w")
print('\n<end page pos =' , i, '>\n')
sys.stdout.close()

Любая идея, как сделать трюк извлечения/разделения страниц и сохранить все в файл?...

Ответы

Ответ 1

В вашем коде вы извлекаете текст, но вы ничего не делаете с ним.

Попробуйте что-то вроде этого:

def extract_txt(file_path):
    text = textract.process(file_path, method='tesseract')
    outfn = file_path[:-4] + '.txt'  # assuming filenames end with '.pdf'
    with open(outfn, 'wb') as output_file:
        output_file.write(text)
    return file_path

Это записывает текст в файл с тем же именем, но с расширением .txt.

Он также возвращает путь к исходному файлу, чтобы родитель знал, что этот файл выполнен.

Поэтому я бы изменил код отображения на:

p = multiprocessing.Pool()
file_path = ['/Users/user/Desktop/sample.pdf']
for fn in p.imap_unordered(extract_txt, file_path):
    print('completed file:', fn)
  • Вам не нужно указывать аргумент при создании Pool. По умолчанию он будет создавать столько рабочих, сколько есть cpu-core.
  • Использование imap_unordered создает итератор, который начинает давать значения, как только они будут доступны.
  • Поскольку функция-работник возвращает имя файла, вы можете распечатать его, чтобы пользователь знал, что этот файл выполнен.

Изменить 1:

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

Метод, который, несомненно, будет работать, заключается в разделении PDF файла на страницы перед OCR. Вы можете использовать, например. pdfinfo из пакета poppler-utils, чтобы узнать количество страниц в документе. И тогда вы можете использовать, например. pdfseparate из того же пакета poppler-utils, чтобы преобразовать один PDF файл из N страниц в файлы N PDF на одной странице. Затем вы можете разделить отдельные PDF файлы отдельно. Это даст вам текст на каждой странице отдельно.

В качестве альтернативы вы можете открыть весь документ, а затем выполнить поиск разрывов страниц. Это будет работать, только если документ имеет постоянный или предсказуемый заголовок или нижний колонтитул на каждой странице. Это, вероятно, не так надежно, как вышеупомянутый метод.


Изменить 2:

Если вам нужен файл, напишите файл:

from PyPDF2 import PdfFileWriter, PdfFileReader
import textract

def extract_text(pdf_file):
    inputpdf = PdfFileReader(open(pdf_file, "rb"))
    outfname = pdf_file[:-4] + '.txt' # Assuming PDF file name ends with ".pdf"
    with open(outfname, 'w') as textfile:
        for i in range(inputpdf.numPages):
            w = PdfFileWriter()
            w.addPage(inputpdf.getPage(i))
            outfname = 'page{:03d}.pdf'.format(i)
            with open(outfname, 'wb') as outfile:  # I presume you need `wb`.
                w.write(outfile)
            print('page', i)
            text = textract.process(outfname, method='tesseract')
            # Add header and footer.
            text = '\n<begin page pos = {}>\n'.format(i) + text + '\n<end page pos = {}>\n'.format(i)
            # Write the OCR-ed text to the output file.
            textfile.write(text)
            os.remove(outfname)  # clean up.
            print(text)