Простой способ извлечения изображений из документов MS и Libre Office
Стандарт Open Document стал де-факто уже давно. И если раньше формат документов Microsoft Office был проприетарным, то теперь он представляет собой «.zip»-файл в котором храниться множество «.xml», а также изображения и прочие файлы. Конечно же, самым простым способом извлечь документы является изменение расширения документа на «.zip» и последующее извлечение файлов любым архиватором. Но, если вам нужно сделать это не с одним документом, это может быть достаточно продолжительно по времени. Поэтому, давайте рассмотрим несколько способов, с помощью которых можно извлечь изображения из файлов формата ".docx", ".xlsx", ".pptx", ".odp", ".ods", ".odt".
Способ №1: используем стандартные библиотеки python
Для данного способа не требуется установка сторонних библиотек. Достаточно тех, что поставляются в комплекте с самим интерпретатором.Создадим файл extract.py.
Импортируем нужные нам в процессе работы библиотеки:
import shutil import zipfile from pathlib import Path
Создадим функцию image_extract(in_zip: zipfile, out_dir: Path), в которую будем передавать zip-файл, а также путь к директории в которую будут распакованы изображения. В данном случае путь у пользователя запрашиваться не будет.Объявим переменную cnt, которая будет счетчиком распакованных изображений. Затем в цикле пробежимся по списку содержимого архива. Проверим расширения файлов в архиве. И если они совпадают с расширениями из списка, будем читать текущий файл с изображением и сохранять в байтовом режиме в директорию, которая передается в функцию. Также, данная директория создается автоматически и называется именем исходного документа. После того, как все изображения будут сохранены, возвращаем из функции наш счетчик.
def image_extract(in_zip: zipfile, out_dir: Path) -> int: cnt = 0 for info in in_zip.infolist(): if Path(info.filename).suffix in [".png", ".jpg", ".jpeg", ".gif"]: Path(out_dir).mkdir(exist_ok=True) content = in_zip.read(info) with open(out_dir / Path(info.filename).name, "wb") as img: img.write(content) cnt += 1 return cnt
Осталось дело за малым, запросить у пользователя путь к файлу, проверить, является ли он файлом и имеет ли нужный формат. После чего скопировать файл с расширением «.zip», открыть с помощью zipfile и передать в функцию для поиска изображений и их распаковки. Ну и напоследок удалить скопированный zip-файл.После окончания извлечения изображений вывести сообщение пользователю о том, сколько файлов было извлечено и в какую директорию.
def main(): out_dir = "" path_file = input("Enter file path: ") if Path(path_file).is_file() and Path(path_file).suffix in [".docx", ".xlsx", ".pptx", ".odp", ".ods", ".odt"]: out_dir = Path.cwd() / Path(path_file).name.removesuffix(Path(path_file).suffix) path_zip = Path(path_file).parent / f"{Path(path_file).name.removesuffix(Path(path_file).suffix)}.zip" if not path_zip.exists(): shutil.copy2(path_file, path_zip) with zipfile.ZipFile(path_zip) as in_zip: cnt = image_extract(in_zip, out_dir) Path(path_zip).unlink() else: print("[~] The path specified is not a file path or is not a MS Office document.") if cnt > 0: print(f"[!] Extract images: [{cnt}] in directory: [{out_dir}]") else: print("[~] There are no images to extract.") if __name__ == "__main__": main()
import shutil import zipfile from pathlib import Path def image_extract(in_zip: zipfile, out_dir: Path) -> int: cnt = 0 for info in in_zip.infolist(): if Path(info.filename).suffix in [".png", ".jpg", ".jpeg", ".gif"]: Path(out_dir).mkdir(exist_ok=True) content = in_zip.read(info) with open(out_dir / Path(info.filename).name, "wb") as img: img.write(content) cnt += 1 return cnt def main(): out_dir = "" path_file = input("Enter file path: ") if Path(path_file).is_file() and Path(path_file).suffix in [".docx", ".xlsx", ".pptx", ".odp", ".ods", ".odt"]: out_dir = Path.cwd() / Path(path_file).name.removesuffix(Path(path_file).suffix) path_zip = Path(path_file).parent / f"{Path(path_file).name.removesuffix(Path(path_file).suffix)}.zip" if not path_zip.exists(): shutil.copy2(path_file, path_zip) with zipfile.ZipFile(path_zip) as in_zip: cnt = image_extract(in_zip, out_dir) Path(path_zip).unlink() else: print("[~] The path specified is not a file path or is not a MS Office document.") if cnt > 0: print(f"[!] Extract images: [{cnt}] in directory: [{out_dir}]") else: print("[~] There are no images to extract.") if __name__ == "__main__": main()
Протестируем созданный скрипт. У нас есть, для примера документ «CustomTkinter.docx». В нем содержаться несколько изображений. Вот их мы и попробуем извлечь.Запускаем скрипт, указываем путь к документу и получаем папку с названием документа, в которой содержаться изображения.
Способ №2: используем библиотеку docx2txt
Создадим файл docx2im.py. В данном случае мы будем использовать стороннюю библиотеку docx2txt. Для ее установки пишем в терминале или командной строке:
pip install docx2txt
Теперь импортируем нужные библиотеки в скрипт.
""" pip install docx2txt """ from pathlib import Path import docx2txt
В данном случае нам не понадобиться создавать дополнительных функций. Сделаем все в одной. Хотя, в теории, можно было бы разделить извлечение изображений и текста. Да, дополнительным бонусом, при том, что извлекаются изображения только из документов «.docx», является извлечение текста.
Для начала запросим у пользователя путь к документу и путь к папке для извлечения изображений. Проверим, является ли переданный параметр путем к документу и является ли расширение данного документа «.docx». Затем проверим, существует ли директория для извлечения изображений. Если нет, создадим ее, так как docx2txt ее самостоятельно не создает.Теперь передаем путь к документу и путь для извлечения изображений в функцию process данной библиотеки. Из нее будет возвращен текст документа. Проверим, содержится ли в переменной text что-нибудь. Для этого обрежем пробелы и знаки переноса каретки, так как, если в документе нет текста, но есть пустая строка, переменна text не будет пуста.Затем открываем текстовый документ на запись и записываем в него полученный текст.
def main() -> None: docx_path = input("Enter document path '.docx': ") out_img_path = input("Enter a path to save the images: ") if Path(docx_path).is_file() and Path(docx_path).suffix == ".docx": if not Path(out_img_path).exists(): Path(out_img_path).mkdir(exist_ok=True) text = docx2txt.process(docx_path, out_img_path) if text: with open(Path.cwd() / f"{Path(docx_path).name.removesuffix(Path(docx_path).suffix)}.txt", "w", encoding="utf-8") as txt: txt.write(text) else: print("The file is not '.docx'.") if __name__ == "__main__": main()
Этот способ достаточно простой, но, как вы уже поняли, извлекать изображения из других форматов документов он не умеет.
Думаю, что вышеприведенных скриптов будет достаточно. Можно использовать также библиотеку aspose-words, которая устанавливается с помощью команды:
pip install aspose-words
Однако, способ извлечения с ее помощью изображений не особо отличается от предыдущих. Создадим файл aspose_extract.py. Вот для примера код:
from pathlib import Path import aspose.words as aw def extract_image(docx_path, out_img_path): cnt = 0 doc = aw.Document(docx_path) shapes = doc.get_child_nodes(aw.NodeType.SHAPE, True) for shape in shapes: shape = shape.as_shape() if shape.has_image: if not Path(out_img_path).exists(): Path(out_img_path).mkdir(exist_ok=True) image = f"image_{cnt}{aw.FileFormatUtil.image_type_to_extension(shape.image_data.image_type)}" shape.image_data.save(str(Path(out_img_path) / image)) cnt += 1 def main(): docx_path = input("Enter document path '.docx': ") out_img_path = input("Enter a path to save the images: ") if Path(docx_path).is_file() and Path(docx_path).suffix == ".docx": extract_image(docx_path, out_img_path) if __name__ == "__main__": main()
Выбирать, что использовать вам и в каком виде, конечно же, вам. Здесь описаны только несколько способов, с помощью которых можно проделать данную операцию. Скорее всего, если поискать более тщательно, найдется еще множество библиотек, с помощью которых можно извлечь изображения из документов.
А на этом все. Спасибо за внимание.
Надеюсь, данная информация будет вам полезна.
Не забудь подписаться на наши телеграм каналы!