Понимание списка Python слишком медленное - PullRequest
0 голосов
/ 09 июня 2018

У меня есть 231 файл PDF, и я хотел бы преобразовать каждый из них в строковый формат.Впоследствии я сохраню каждую из этих строк в текстовом файле.

Мне удалось создать код для этого (я проверил, что он работает, когда я запускаю код для меньшего числа элементов), ноPython не завершил выполнение программы даже через 10 часов!

Я попробовал тот же код, используя "for loop", но он тоже слишком медленный.Любая идея, как я мог бы сделать этот код быстрее?

Вот мой код:

from pdfminer.pdfinterp import PDFResourceManager, 
PDFPageInterpreter#process_pdf
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

from io import StringIO

def pdf_to_text(pdfname):

    # PDFMiner boilerplate
    rsrcmgr = PDFResourceManager()
    sio = StringIO()
    codec = 'utf-8'
    laparams = LAParams()
    device = TextConverter(rsrcmgr, sio, codec=codec, laparams=laparams)
    interpreter = PDFPageInterpreter(rsrcmgr, device)

    # Extract text
    fp = open(pdfname, 'rb')
    for page in PDFPage.get_pages(fp):
        interpreter.process_page(page)
    fp.close()

    # Get text from StringIO
    text = sio.getvalue()

    # Cleanup
    device.close()
    sio.close()

    return text

lista2 = [pdf_to_text(k) for k in lista1]

Где lista1 это список с моими 231 PDF

PDF-файлыбыли выдержки из этого веб-сайта .Я выбрал только файлы со словом «Livro» в названии.

Ответы [ 2 ]

0 голосов
/ 09 июня 2018

Похоже, файлы, которые вы обрабатываете, довольно большие (10 МБ), поэтому ожидается длительное время выполнения.Вы не можете ничего сделать, чтобы ускорить выполнение вашей программы, кроме большего распараллеливания и большей осторожности с памятью.То есть вы можете делать следующее:

  • использовать многопоточность с multiprocessing.Pool
  • записывать каждый текстовый файл на диск отдельно, чтобы освободить память

Вот полная программа с этими оптимизациями:

#!/usr/bin/env python

import os

from multiprocessing import Pool, cpu_count
from io import BytesIO

from pdfminer.pdfinterp import PDFResourceManager, PDFPageInterpreter
from pdfminer.pdfpage import PDFPage
from pdfminer.converter import TextConverter
from pdfminer.layout import LAParams

PDF_DIRECTORY = "pdfs"


def pdf_to_text(pdf_filename):
    # PDFMiner boilerplate
    pdf_resource_manager = PDFResourceManager()
    bytes_io = BytesIO()
    device = TextConverter(
        pdf_resource_manager, bytes_io, codec="utf-8", laparams=LAParams())
    interpreter = PDFPageInterpreter(pdf_resource_manager, device)

    # Extract text
    with open(pdf_filename, "rb") as fp:
        for page in PDFPage.get_pages(fp):
            interpreter.process_page(page)

    text = str(bytes_io.getvalue())

    # Cleanup
    bytes_io.close()
    device.close()

    # Print current filename with some of the parsed text
    print("{} - {}".format(pdf_filename, text[:15].replace("\n", "")))

    return text


def process_pdf_file(pdf_filename):
    text_filename = "{}.txt".format(os.path.splitext(pdf_filename)[0])

    # Write the text file to disk to avoid having to keep
    # it in memory
    with open(text_filename, "w") as text_file:
        text_file.write(pdf_to_text(pdf_filename))


def main():
    pdf_filename_list = []
    for filename in os.listdir(PDF_DIRECTORY):
        if not filename.endswith(".pdf"):
            continue
        pdf_filename_list.append(os.path.join(PDF_DIRECTORY, filename))

    MULTITHREAD = True
    if MULTITHREAD:
        # Use a thread pool to process multiple PDF files at the same time
        pool = Pool(cpu_count())
        pool.map(process_pdf_file, pdf_filename_list)
    else:
        # Version without thread pool
        for pdf_filename in pdf_filename_list:
            process_pdf_file(pdf_filename)


main()
0 голосов
/ 09 июня 2018

Это один из лучших вариантов использования генераторов: сохранение памяти.

Часто все, что вам нужно сделать, - это перебирать файлы, преобразовывать по одному и передавать поток в другое место.Скажем, например:

for f in files:
   text = pdf_to_text(f)
   output.write(text)

- тогда вам не нужно (или не нужно) понимание списка, фактически вам вообще не нужно создавать список.Вместо этого рассмотрите возможность перебора элементов по одному.Или создайте генератор, если это имеет больше смысла.

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

Следует также учитывать возможность обработки больших файлов, даже если вы можете выполнить allocate / transform /deallocate все еще может быть "слишком медленным", если мы говорим о многих гигабайтах, которые стоит прочитать / записать.В этом случае лучшая альтернатива часто рассматривает возможность использования расширений C, которые обеспечат лучший контроль над тем, как распределяется и используется память.Кроме того, pypy работает в подавляющем большинстве случаев и обычно намного быстрее, чем CPython.

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