Поисковик PDF-файлов Python переполняет оперативную памятьPython

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Поисковик PDF-файлов Python переполняет оперативную память

Сообщение Anonymous »

В рамках моей программы я пытаюсь использовать стороннюю библиотеку pdfminer на Python, чтобы открывать и читать страницы PDF, а затем использовать регулярные выражения для поиска определенных шаблонов. Я также использую многопроцессорную обработку для распараллеливания этого процесса, поскольку мне нужно проанализировать большое количество PDF-файлов. Каждый процесс должен обрабатывать один PDF-файл.
У меня есть этот код для настройки многопроцессорности:

Код: Выделить всё

def process_theme_files(theme_dir: Path, processed_files: Optional[Set[str]] = None, theme_processed_files: Optional[Set[str]] = None) -> Tuple[List[Tuple[str, int, str, str, str, str, str, str]], List[Exception]]:
"""
Processes files of a specific theme in a multiprocessed manner.

Parameters:
- theme_dir (Path): Path object pointing to the theme directory.
- processed_files (set, optional): Set of globally processed files. Defaults to None.
- theme_processed_files (set, optional): Set of files processed in the current theme. Defaults to None.

Returns:
- Tuple[List[Tuple[str, int, str, str, str, str, str, str]], List[Exception]]: A tuple containing a list of tuples
containing extracted information from the theme files and a list of exceptions encountered during the processing.
"""
results = []
exceptions = []

# Number of processes to be used (can be adjusted as needed)
num_processes = multiprocessing.cpu_count()

# Initialize processed_files and theme_processed_files as empty sets if not provided
if processed_files is None:
processed_files = set()
if theme_processed_files is None:
theme_processed_files = set()

# Get PDF files in the theme directory
pdf_files = list(theme_dir.glob('**/*.pdf'))

# Create progress bar
with tqdm(total=len(pdf_files), desc='Processing PDFs', unit='file') as pbar:
# Process PDF files in parallel using ProcessPoolExecutor
with concurrent.futures.ProcessPoolExecutor(max_workers=num_processes) as executor:
# Map the process_file function to each PDF file in the list
future_to_file = {executor.submit(process_file, pdf_file): pdf_file for pdf_file in pdf_files}

# Iterate over results as they become available
for future in concurrent.futures.as_completed(future_to_file):
pdf_file = future_to_file[future]
try:
# Get the result of the task
file_results, file_exceptions = future.result()
# Extend the results list
results.extend(file_results)
# Append specific exceptions to the exceptions list
exceptions.extend(file_exceptions)
except FileNotFoundError as fnfe:
exceptions.append(f"File not found: {fnfe.filename}")
except Exception as e:
# Capture and log the generic exception
exceptions.append(f"Error processing file '{pdf_file}': {e}")

# Update the progress bar
pbar.update(1)

return results, exceptions
И этот код для обработки отдельных файлов:

Код: Выделить всё

def process_file(file_path: Path):
"""
Process a PDF file to extract text and information.

Args:
- file_path (Path): Path object representing the location of the PDF file.

Returns:
- Tuple[List, List]: A tuple containing two lists:
1. List of extracted results.
2.  List of encountered exceptions during processing.

Raises:
- FileNotFoundError: If the specified file_path does not exist.
- Exception: For any other unexpected errors during processing.
"""
results = []        # List to store extracted information from each page
exceptions = []     # List to store exceptions encountered during processing

try:
# Check the size of the PDF file
pdf_size_bytes = os.path.getsize(file_path)
pdf_size_mb = pdf_size_bytes / (1024 * 1024)

# Check if the PDF file size exceeds the maximum allowed size
if pdf_size_mb > MAX_PDF_SIZE_MB:
exceptions.append((file_path, f"The file exceeds the maximum allowed size of {MAX_PDF_SIZE_MB} MB."))
print(f'{file_path} - Exceeds maximum allowed size of {MAX_PDF_SIZE_MB} MB.')
return results, exceptions

# Open the PDF file and read its content into a BytesIO buffer
with file_path.open('rb') as file:
pdf_data_buffer = BytesIO(file.read())

# Iterate through each page of the PDF
for page_number, page in enumerate(PDFPage.get_pages(pdf_data_buffer, check_extractable=True)):
# Extract text from the current page
page_text = extract_text(pdf_data_buffer, page_numbers=[page_number])

# Process the extracted text to extract information
page_results, page_exceptions = extract_information(page_text, file_path.name, page_number + 1)  # Page numbers are 1-based

# Extend results and exceptions lists with page-specific results and exceptions
results.extend(page_results)
exceptions.extend(page_exceptions)

except FileNotFoundError as e:
# Handle case where the file does not exist
exceptions.append(e)
print(f"FileNotFoundError: {e}")
raise

except Exception as e:
# Handle any other unexpected exceptions
exceptions.append(e)
print(f"Exception: {e}")
raise

return results, exceptions
Проблема в том, что мне не хватает оперативной памяти, даже если установлено 32 ГБ:
Изображение

Благодаря своим исследованиям я узнал, что PDF-файлы нельзя читать случайным образом; их нужно читать последовательно от начала до конца файла, как я это и реализовал.
Некоторые из моих PDF-файлов имеют размер около 100 МБ, но никогда не превышают 200 МБ, и некоторые из них довольно длинные (1000 страниц) и содержат множество изображений. Поскольку мне приходится читать все страницы при обработке PDF-файла, единственным обходным решением, которое я смог найти, было ограничение размера PDF-файлов, которые я читаю, до уровня менее 100 МБ. Я также не могу придумать, как ограничить количество страниц - потому что, чтобы определить количество страниц, мне нужно открыть и прочитать файл.
Как я могу ограничить Использование оперативной памяти в этой программе?

Подробнее здесь: https://stackoverflow.com/questions/788 ... ws-the-ram
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»