Как с помощью Python из файла Word удалить ненужные изображения и таблицы?

R4
На сайте с 01.10.2016
Offline
86
276
После экспорта из PDF в Word (через) в файле остается много не нужных артефактов в тексте:
- бессмысленные части картинок
- пустые таблицы из 1 ячейки

Нужно реализовать следующее решение на базе Python и Google Colab:
1. Добавляю файл Word, через кнопку “загрузить”.
2. Вывести в интерфейсе миниатюры всех изображений и таблиц (в 1 экземпляре) с галочкой рядом.
3. Снимаю галочки у не нужных изображений и таблиц.
4. Подтверждаю.
5. Из файла Word удаляются изображения и таблицы, с которых я снял галочки.
6. Авто-скачивание файла Word на ПК.

Скрипт для удаление изображений и таблиц из Word
Образец файла

Таблица выводит в интерфейс.
Изображения и фигуры из word не выводит. Помогите, пожалуйста, найти ошибку. Что поправить?
S3
На сайте с 29.03.2012
Offline
365
#1
rownong4 :
Скрипт для удаление изображений и таблиц из W

доступ дай к файлу

R4
На сайте с 01.10.2016
Offline
86
#2
Sly32 #:

доступ дай к файлу

Извиняюсь. Спасибо, что подсказал.
Доступ к файлу гугл колаб открыл.

S3
На сайте с 29.03.2012
Offline
365
#3

В твоем коде вместо блока поиска по кртинкам

document.inline_shapes
   for idx, shape in enumerate(document.inline_shapes):
        shape_type = shape.type
        # Получаем родительский элемент run
        parent_run_element = shape._inline.getparent().getparent()
        run = Run(parent_run_element, None)

        if shape_type == WD_INLINE_SHAPE_TYPE.PICTURE:
            # Получаем часть с изображением
            image_part_id = shape._inline.graphic.graphicData.pic.blipFill.blip.embed
            image_part = document.part.related_parts[image_part_id]
            # Получаем данные изображения
            image_data = image_part.blob
        else:
            # Для фигур напрямую получить изображение нельзя
            image_data = None

        shapes_info.append({
            'shape': shape,
            'type': shape_type,
            'run': run,
            'image_data': image_data,
            })

Попробуй сделать так:

            # Handle floating shapes
            for rel in self.document.part.rels.values():
                try:
                    if "image" in rel.target_part.content_type:
                        images.append({
                            'image_data': rel.target_part.blob,
                            'content_type': rel.target_part.content_type
                        })  
                except Exception as e:
                    print(f"Error processing relation: {str(e)}")

Только адаптируй под свой колаб исключения и лист картинок, как тебе надо.

У меня этот код находит в твоем файле 2 картинки. 
Но скорее всего нужно оставить и старый код, потому что в разных доках картинки могут храниться по разному. 

S3
На сайте с 29.03.2012
Offline
365
#4

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

import os
import docx

from docx import Document
import ipywidgets as widgets
from IPython.display import display, clear_output
# from google.colab import files
import io
from PIL import Image
from fastapi import Path
from docx.enum.shape import WD_INLINE_SHAPE_TYPE
from docx.text.run import Run
from docx.oxml.ns import qn
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from structlog import get_logger

logger = get_logger(__name__)

matplotlib.use('Agg')

path_str = os.getcwd()


class WordEditor:

    def __init__(self, file):
        self.file = file
        self.document = None
        self.tables = []
        self.images = []

    def load_file(self):
        if isinstance(self.file, str):
            with open(self.file, 'rb') as f:
                self.document = Document(f)
        else:
            self.document = Document(io.BytesIO(self.file))
        return self.document

    def get_empty_tables(self):
        for i, table in enumerate(self.document.tables):
            if all(not cell.text.strip() for row in table.rows for cell in row.cells):
                self.tables.append(table)
        return self.tables

    def get_images(self):
        """Extract images from both inline shapes and shapes in Word document"""
        images = []

        try:
            # Handle inline shapes (embedded images)
            for shape in self.document.inline_shapes:
                try:
                    if shape.type == WD_INLINE_SHAPE_TYPE.PICTURE:
                        rId = shape._inline.graphic.graphicData.pic.blipFill.blip.embed
                        image_part = self.document.part.related_parts[rId]
                        if image_part and hasattr(image_part, 'blob'):
                            images.append({
                                'image_data': image_part.blob,
                                'content_type': image_part.content_type
                            })
                except Exception as e:
                    logger.error(f"Error processing inline shape: {str(e)}")

            # Handle floating shapes
            for rel in self.document.part.rels.values():
                try:
                    if "image" in rel.target_part.content_type:
                        self.images.append(rel.target_part)
                except Exception as e:
                    logger.error(f"Error processing relation: {str(e)}")

        except Exception as e:
            logger.error(f"Error accessing document: {e}")

        logger.info(f"Found {len(images)} images in document")
        return self.images

    def remove_empty_tables(self):
        """Remove empty tables from document using the result of get_empty_tables."""
        removed_count = 0
        for table in self.tables:
            table._element.getparent().remove(table._element)
            removed_count += 1
        return removed_count

    def remove_images(self):
        """Remove all images from document use self.images."""
        removed_count = 0
        for image in self.images:
            del self.document.part.rels[image.rId]
            removed_count += 1
        return removed_count

    def save_new_document(self):
        """Save self.document with new name with prefix cleared_"""
        new_filename = os.path.join(path_str, "media/cleared_document.docx")
        self.document.save(new_filename)
        return new_filename

if __name__ == "__main__":
    print("path:", path_str)
    filename = os.path.join(path_str, "media/worddoc.docx")
    executor = WordEditor(file=filename)
    executor.load_file()
    executor.get_empty_tables()
    executor.get_images()
    executor.remove_empty_tables()
    executor.remove_images()
    executor.save_new_document()

Авторизуйтесь или зарегистрируйтесь, чтобы оставить комментарий