Как проще и быстрее разбить pdf на часть размером до 5Мб

У меня есть задача копировать файлы pdf из одной папки в другую. Если какие-то файлы pdf более 5Мб то их надо разбить на части до 5Мб.

Я написал функцию, которая с этим справляется (просьба строго не судить) Но проблема в том что эта функция работает оооочень долго для pdf у которых более 100 страниц. А мне требуется обработать сотни тысяч документов

# Переместить и разбить при необходимости pdf
def copy_and_split_pdf(source_pdf_path, output_dir, new_pdf_name, max_pdf_size_mb=5.0):
    report_message = ""
    result_paths_pdf = []

    try:
        file_size_in_mb = get_file_size_in_mb(source_pdf_path)
        if file_size_in_mb > max_pdf_size_mb:
            source_pdf = fitz.open(source_pdf_path)

            result_pdfs_obj = []
            qty_pages = source_pdf.page_count
            from_page = 0
            to_page = qty_pages-1

            while True:
                print(from_page, to_page)
                new_pdf = fitz.open()
                new_pdf.insert_pdf(source_pdf, from_page=from_page, to_page=to_page)
                new_pdf.save("./tmp.pdf")
                pdf_size_mb = get_file_size_in_mb("./tmp.pdf")
                if pdf_size_mb < max_pdf_size_mb:
                    result_pdfs_obj.append(new_pdf)

                    # print(from_page, to_page, pdf_size_mb)
                    if to_page == qty_pages - 1:
                        break
                    from_page = to_page+1
                    to_page = qty_pages-1
                else:
                    if from_page == to_page:
                        for pdf in result_pdfs_obj:
                            pdf.close()
                        result_pdfs_obj = []
                        break
                    to_page -= 1
                new_pdf.close()
            source_pdf.close()

            if len(result_pdfs_obj) == 0:
                report_message = f"Ошибка: не удалось разбить pdf файл {source_pdf_path} на части меньше {max_pdf_size_mb} МБ"
            else:

                if not os.path.exists(output_dir):
                    os.mkdir(output_dir)

                for pdf in result_pdfs_obj:
                    new_pdf_save_name = f"{new_pdf_name}_{result_pdfs_obj.index(pdf)+1}.pdf"
                    save_path = os.path.join(output_dir, new_pdf_save_name)
                    pdf.save(save_path)
                    pdf.close()
                    result_paths_pdf.append(save_path)
        else:

            if not os.path.exists(output_dir):
                os.mkdir(output_dir)

            new_pdf_name = f"{new_pdf_name}.pdf"
            save_path = os.path.join(output_dir, new_pdf_name)
            shutil.copy2(source_pdf_path, save_path)
            result_paths_pdf.append(save_path)

    except Exception as e:
        print(e)
        report_message = f"Ошибка: {e} (Не удалось загрузить файл: {source_pdf_path})"
    finally:
        return report_message, result_paths_pdf

Как еще можно реализовать такой алгоритм чтобы ускорить процесс?


Ответы (1 шт):

Автор решения: Kadenza

Придумал быстрое решение. Но буду благодарен за подсказки

# получить размер файла в Мб
def get_file_size_in_mb(file_path):
    size_in_bytes = os.path.getsize(file_path)
    size_in_mb = size_in_bytes / (1024 * 1024)
    return size_in_mb


# Получить диапазоны страниц для частей файла размером до max_size_mb
def get_range_page_by_size(pdf_obj, max_size_mb, tmp_path=tmp_path_for_files):
    sizes_for_page = []
    count_pages = pdf_obj.page_count
    tmp_path = os.path.join(tmp_path, 'tmp.pdf')

    try:
        for page in range(count_pages):
            new_pdf = fitz.open()
            new_pdf.insert_pdf(pdf_obj, from_page=page, to_page=page)
            new_pdf.save(tmp_path)
            page_size = get_file_size_in_mb(tmp_path)
            os.remove(tmp_path)

            # если размер одной страницы превышает максимальный размер файла
            if page_size > max_size_mb:
                return []

            sizes_for_page.append(page_size)

        ranges = []
        current_range = []
        current_size = 0
        for i, size in enumerate(sizes_for_page):

            if current_size + size <= max_size_mb:
                current_range.append(i)
                current_size += size
            else:
                ranges.append([current_range[0], current_range[-1]])
                current_range = [i]
                current_size = size

        if len(current_range) > 0:
            ranges.append([current_range[0], current_range[-1]])

        return ranges

    except Exception as e:
        print(e)
        return []


# Переместить и разбить при необходимости pdf
def copy_and_split_pdf(source_pdf_path, output_dir, new_pdf_name, max_pdf_size_mb=5.0):
    report_message = ""
    result_paths_pdf = []

    try:
        file_size_in_mb = get_file_size_in_mb(source_pdf_path)
        if file_size_in_mb > max_pdf_size_mb:
            source_pdf = fitz.open(source_pdf_path)
            range_page_by_size = get_range_page_by_size(source_pdf, max_size_mb=max_pdf_size_mb)

            if len(range_page_by_size) == 0:
                report_message = f"Ошибка: не удалось разбить pdf файл {source_pdf_path} на части меньше {max_pdf_size_mb} МБ"
            else:
                post_index = 1

                if not os.path.exists(output_dir):
                    os.mkdir(output_dir)

                for from_page, to_page in range_page_by_size:
                    new_pdf = fitz.open()
                    new_pdf.insert_pdf(source_pdf, from_page=from_page, to_page=to_page)
                    new_pdf_save_name = f"{new_pdf_name}_{post_index}.pdf"
                    save_path = os.path.join(output_dir, new_pdf_save_name)
                    new_pdf.save(save_path)
                    new_pdf.close()
                    result_paths_pdf.append(save_path)
                    post_index += 1
        else:

            if not os.path.exists(output_dir):
                os.mkdir(output_dir)

            new_pdf_name = f"{new_pdf_name}.pdf"
            save_path = os.path.join(output_dir, new_pdf_name)
            shutil.copy2(source_pdf_path, save_path)
            result_paths_pdf.append(save_path)

    except Exception as e:
        print(e)
        report_message = f"Ошибка: {e} (Не удалось загрузить файл: {source_pdf_path})"
    finally:
        return report_message, result_paths_pdf
→ Ссылка