Простой способ извлечения изображений из документов 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()
Выбирать, что использовать вам и в каком виде, конечно же, вам. Здесь описаны только несколько способов, с помощью которых можно проделать данную операцию. Скорее всего, если поискать более тщательно, найдется еще множество библиотек, с помощью которых можно извлечь изображения из документов.
А на этом все. Спасибо за внимание.
Надеюсь, данная информация будет вам полезна.
Не забудь подписаться на наши телеграм каналы!