IT-инфраструктура для бизнеса и творчества
Разработка
NTA

Заполняем PDF файлы с использованием Python: библиотека python-pptx

Нам часто приходится заполнять шаблоны, бланки и прочие документы. Если операция повторяется постоянно, то работу нужно автоматизировать. Сегодня расскажем о создании умного шаблона, а также об автоматизации процесса его заполнения.

Это может помочь, к примеру, в автоматизации заполнения шаблонов презентаций: для ежеквартальный отчетов, выступлений, текущих задач и новых идей.

С одной стороны, создание слайдов – это творческий процесс и при автоматизации пропадает индивидуальный подход и творчество. Но это нет так. Рутинную работу мы передаем роботу, а творчество используем в создании умного шаблона. Преимущества: исключаем ошибки при переносе информации из одного формата (Excel, Word) в другой и отказываемся от ручного процесса переноса.

Впервые автозаполнение слайдов в Power Point с помощью Python — мы использовали для подготовки наградных документов по результатам работы сотрудников за год. Так как номинаций было несколько – получился большой список сотрудников.

Поэтому хотим поделиться своим практическим опытом автоматизации этого процесса. Опираясь на него, вы также сможете создать свой умный шаблон для решения текущих задач.

  • Какие инструменты использовали:Microsoft PowerPoint, Jupyter Notebook, MS Excel, Adobe Photoshop (или можно найти готовый шаблон в сети Интернет)
  • Язык программирования: Python

1. Библиотеку для обработки файлов *.pptx устанавливаем через командную строку или Anaconda Prompt – pip install python-pptx

3. Далее на фоновое изображение необходимо наложить текст и другие элементы, которые будут оставаться неизменными. Используем для этого — MS PowerPoint.

4. Информацию по всем сотрудникам, заявленным к награждению, мы вносим в файл Excel (его же будем использовать как источник данных).

5. Используя инструмент интерактивной разработки Jupyter Notebook импортируем библиотеку pptx и модули этой библиотеки. Для чтения excel импортируем библиотеку xlrd.

from pptx import Presentation from pptx.enum.shapes import … …. import os import xlrd workbook=xlrd.open_workbook('./Название файла, содержащего список ФИО награждаемых')

6. С помощью следующего блока программного кода читаем данные из Excel-листа в Python framework.

worksheet=workbook.sheet_by_index(4) total_rows=worksheet.nrows total_cols=worksheet.ncols table=list() record=list() if total_rows > 0: for x in range(7,total_rows): # не берем строки с 1 по 7, в которых текст и названия столбцов for y in range(total_cols): record.append(worksheet.cell(x,y).value) table.append(record) record = [ ] x=x+1 else: print("Файл пустой")

7. Указываем место на локальном диске, в котором будет создана папка для наших наградных электронных документовlocalpath=’c:\\папка_1\\папка_2\\’

8. Создаем функцию, c помощью которой обратим pptx-файл в pdf-файл.

def PPTtoPDF(inputFileName, outputFileName, formatType = 32): powerpoint = comtypes.client.CreateObject("Powerpoint.Application") powerpoint.Visible = 1 if outputFileName[-3:] != 'pdf': outputFileName = outputFileName + ".pdf" deck = powerpoint.Presentations.Open(inputFileName) deck.SaveAs(outputFileName, formatType) # formatType = 32 for ppt to pdf deck.Close() powerpoint.Quit()

9. Соблюдаем правила орфографии и склонения с помощью следующего блока кода:

for i in range(total_rows-7): # не берем первые 7 строк (там "шапка") #print(i) record=table[i] if record[0]!="": # если столбец "Кто номинирует" НЕ пустой (в таблице больше строк,чем внесено данных) company='ООО Ромащка ' city= record[4] if city=='МСК': city='г.Москва' companycity=company+city

10. Заполняем информацию по занятым местам:

mesto = str(record[2]) if mesto=='1.0': mesto='I' _mesto=mesto #для имени файла mesto1=' занявшее в номинации' # оставляем разное кол-во пробелов для печати места др.цветом mesto2=mesto+" место " if mesto=='2.0': mesto='II' _mesto=mesto #для имени файла mesto1=' занявшее в номинации' mesto2=mesto+" место " if mesto=='3.0': mesto='III' _mesto=mesto #для имени файла mesto1=' занявшее в номинации' mesto2=mesto+" место " if mesto=='1.5': mesto='I-II' _mesto=mesto #для имени файла mesto1=' занявшее в номинации' mesto2=mesto+" место " if mesto=='2.5': mesto='II-III' _mesto=mesto #для имени файла mesto1=' занявшее в номинации' mesto2=mesto+" место " if mesto=='3.5': mesto='III-IV' _mesto=mesto #для имени файла mesto1=' занявшее в номинации' mesto2=mesto+" место " if mesto=='': _mesto='победитель' # для имени файла mesto1='победитель в номинации' mesto2='' nom = record[1] za = record[3]

11. Теперь формируем текст для печати, устанавливаем отступы, задаем цвет текстовым слоям:

if za!='': #есть "за что" #формируем текст для печати [1-company+city,2-mesto1,3-mesto2,4-nom,5-za] dtop = {1: Cm(7.0), 2: Cm(8.5), 3: Cm(8.5), 4: Cm(10.0), 5: Cm(11.5)} dalign = {1:PP_ALIGN.CENTER,2:PP_ALIGN.CENTER,3:PP_ALIGN.CENTER,4:PP_ALIGN.CENTER,5:PP_ALIGN.CENTER} dfsize = {1: Pt(20),2: Pt(20),3: Pt(20),4: Pt(20), 5: Pt(20)} dfcolor = {1:RGBColor(38,38,38),2:RGBColor(38,38,38),3:RGBColor(9,137,55),4:RGBColor(38,38,38),5:RGBColor(38,38,38)} dfbold= {1:True,2:False,3:False,4:True,5:False} dtext = {1:companycity,2:mesto1,3:mesto2,4:nom,5:za} else: # нет "за что" #формируем текст для печати [1-company+city,2-mesto1,3-mesto2,4-nom] dtop = {1: Cm(7.5), 2: Cm(9.5),3: Cm(9.5), 4: Cm(11.5)} dalign = {1:PP_ALIGN.CENTER,2:PP_ALIGN.CENTER,3:PP_ALIGN.CENTER,4:PP_ALIGN.CENTER} dfsize = {1: Pt(20),2: Pt(20),3: Pt(20),4: Pt(20)} dfcolor = {1:RGBColor(38,38,38),2:RGBColor(38,38,38),3:RGBColor(9,137,55),4:RGBColor(38,38,38)} dfbold= {1:True,2:False,3:False, 4:True} dtext = {1:uvabank,2:mesto1,3:mesto2,4:nom}

12. Затем формируем итоговые pdf-файлы (устанавливаем шрифт, цвет, размер)

q=len(dtext) # кол-во элементов для печати nameprs='ДИПЛОМ' # ВНИМАНИЕ: шаблоны с именами должны лежать в каталоге вместе с программой prs=Presentation(nameprs + ".pptx") slide = prs.slides[0] shapes = slide.shapes for j in range(1,q+1): shape = shapes.add_shape(MSO_SHAPE.RECTANGLE, Cm(1.25), dtop[j], Cm(25.0), Cm(2)) shape.fill.background() shape.line.fill.background() shape.shadow.inherit = False text_frame = shape.text_frame text_frame.vertical_anchor = MSO_ANCHOR.TOP p = text_frame.paragraphs[0] p.alignment = dalign[j] run = p.add_run() font = run.font font.name = 'Arial' font.italic = None # cause value to be inherited from theme font.bold=dfbold[j] #font.color.rgb=RGBColor(38,38,38) font.color.rgb=dfcolor[j] run.text = dtext[j] font.size = dfsize[j] fname=localpath + record[4] +'_'+'ДИПЛОМ'+'_'+ nom +'_'+_mesto+" "+str(i+8) # ИМЯ ВЫХОДНОГО ФАЙЛА_"ДИПЛОМ"_номинация_место_№строки в файле prs.save(fname + '.pptx') PPTtoPDF(fname + '.pptx',fname + '.pdf') #os.remove(fname.replace('\\','/')+'.pptx') не удаляем файл .pptx i=i+1 # закончили формирование дипломов

Итоговый продукт выглядит следующим образом.

{ "author_name": "NTA", "author_type": "editor", "tags": ["\u0444\u043e\u0440\u043c\u0438\u0440\u0443\u0435\u043c","\u0435\u0441\u0442\u044c","\u0434\u043b\u044f","selectel_\u0438\u043d\u0441\u0442\u0440\u0443\u043a\u0446\u0438\u044f","print","os","font"], "comments": 0, "likes": 4, "favorites": 23, "is_advertisement": false, "subsite_label": "dev", "id": 159113, "is_wide": true, "is_ugc": false, "date": "Thu, 17 Sep 2020 15:15:29 +0300", "is_special": false }
(function () { let cdnUrl = `https://specialsf378ef5-a.akamaihd.net/SelectelBranding/images/` let previousArticleNumber = null let currentArticleNumber = 0 let platform = 'Desktop' let articles = [ // { // name: 'camera', // url: `${cdnUrl}CameraCat`, // text: 'умную камеру для\u00A0наблюдения за\u00A0котиками', // link: '1', // }, { name: 'chill', url: `${cdnUrl}ChillCat`, text: 'трекер, который подскажет, когда пора отдохнуть', link: 'https://vc.ru/promo/288561-eye-tracker', }, // { // name: 'cloud', // url: `${cdnUrl}CloudCat`, // text: 'котика: даёшь ему «пять», а\u00A0он делает бэкап в облако', // link: '3', // } ] let buttonCycle = document.querySelector('.button--cycle') let textField = document.querySelector('.selectel-footer-subtitle') let imageAgent = document.querySelector('.image--agent') let banner = document.querySelector('.selectel-footer') buttonCycle.addEventListener('click', cycleClick) let media = window.matchMedia("(max-width: 570px)") media.addEventListener('change', matchMedia) function matchMedia() { if (media.matches) { platform = 'Mobile' } else { platform = 'Desktop' } update() } matchMedia() function cycleClick(event) { if (event) { event.preventDefault() event.stopPropagation() } window.open('https://vc.ru/tag/selectelDIY', '_blank') //cycle(event) } function cycle(event) { // incrementArticleNumber() textField.innerHTML = generatedText() imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?5' imageAgent.setAttribute("class", "") imageAgent.classList.add('image--agent', articles[currentArticleNumber].name) banner.href = articles[currentArticleNumber].link } function update() { banner.href = articles[currentArticleNumber].link imageAgent.src = articles[currentArticleNumber].url + platform + '.svg?5' textField.innerHTML = generatedText() } function incrementArticleNumber() { previousArticleNumber = currentArticleNumber if (currentArticleNumber >= articles.length - 1) { currentArticleNumber = 0 } else { currentArticleNumber++ } } function generatedText() { let defaultText if (platform === 'Desktop') { defaultText = `Мы тут собрали %text%. Хотите почитать?` } else { defaultText = `Мы тут собрали %text%.` } return defaultText.replace('%text%', articles[currentArticleNumber].text) } function getRandom(min, max) { min = Math.ceil(min) max = Math.floor(max) return Math.floor(Math.random() * (max - min + 1)) + min } (function create() { currentArticleNumber = getRandom(0, articles.length - 1) cycle() let page = document.querySelector('.page--entry') if (page) { function insertAfter() { let parents = page.querySelectorAll('[data-id="7"]') let referenceNode = parents[0] referenceNode.parentNode.insertBefore(banner, referenceNode.nextSibling); loaded() } setTimeout(() => insertAfter(), 0) } }()) function loaded() { banner.classList.add('loaded') } loadImages([ `${cdnUrl}CameraCatDesktop.svg`, `${cdnUrl}ChillCatDesktop.svg`, `${cdnUrl}CloudCatDesktop.svg`, `${cdnUrl}CameraCatMobile.svg`, `${cdnUrl}ChillCatMobile.svg`, `${cdnUrl}CloudCatMobile.svg`, ]) function loadImages(urls) { return Promise.all(urls.map(function (url) { return new Promise(function (resolve) { var img = document.createElement('img'); img.onload = resolve; img.onerror = resolve; img.src = url; }); })); } }())
0
0 комментариев
Популярные
По порядку
Читать все 0 комментариев
Переход бизнеса на Apple: нет причин отказывать себе в удовольствии

Работать на устройствах Apple – это просто, удобно, приятно, современно. А еще, как продолжают считать некоторые – дорого и не для всех. Однако это не так: хотя «яблочные» устройства и работают в каждой международной корпорации из Fortune 500, сегодня они доступны практически любой SMB-компании, стартапу, и даже общеобразовательной школе. Причина кроется как в самих технологиях Apple, так и в выстроенных вокруг них сервисных программах.

Как мы проводили командную ретроспективу в Minecraft

Рассказываем историю, на что стоит обратить внимание при проведении командного мероприятия в игре Minecraft, какие грабли могут быть, как организовать онлайн- и офлайн-участие.

БКС не выполняет свои условия по акции

У БКС сейчас якобы проходит акция для новых клиентов. Дают акции компании ПИК, взависимости от суммы пополнения брокерского счёта. На сайте есть форма для заполнения паспортных данных, номера телефона и тд. После её заполнения якобы должен прийти пароль на номер для входа в приложение.

Министерство транспорта предложило устанавливать в такси устройства контроля за усталостью водителя Статьи редакции

И размещать на крыше автомобиля оранжевый фонарь.

Как традиционному малому бизнесу превратиться в стартап: план действий

Сейчас в России предприниматели переходят из традиционного малого бизнеса в стартапы очень редко — меньше чем в 0,02% случаев. Это не больше 1 000 стартапов из около 6 млн предприятий малого бизнеса. Поговорим о том, что мешает предпринимателям и как действовать, если есть желание создать стартап.

Повелись на красивые кейсы таргетологов из «Hope group» и вот что из этого вышло

В августе я наткнулся на vc.ru не кейсы ребят из «Hope group», с ними вы можете ознакомиться по этой ссылке. И на удивление кейсы показались супер адекватными ведь в них ребята оперируют не кликами, показами и прочими ничего не значащими показателями, а конкретными продажами и конверсиями. Я связался с основателем и в сентябре мы подписали…

Нужны ли в России сити-фермы

И появятся ли грядки на крышах пятиэтажек.

re-thinkingthefuture.com
«На новую систему потратили не более 1 млн рублей»: баттл предпринимателей о том, как модель управления бизнесом лучшая

Владельцы «Перилаглавснаб», Gartel, Compleader и «Архитектуры благополучия» — о том, почему модные «бирюзовые организации» не для всех, как выдержать трёхкратный рост бизнеса и не работать по 14 часов в день.

Из жизни клуба
Сергей Галицкий о деньгах: «В гробу карманов нет. Два завтрака съесть не сможешь» Статьи редакции

В сентябре бизнесмен сообщил о своей болезни, которая мешает ему работать.

Во-первых, следующее поколение должно иметь мотивацию. Во-вторых, в гробу карманов нет. Ты заработал в этом обществе. И ты должен отдавать этому обществу. Два завтрака ты съесть не сможешь, как ни пытайся. Второй завтрак уже будет полдником.

Ты не можешь употребить больше двух-трёх тысяч калорий в день. Тебе не нужно столько. Не нужно двадцать машин, тридцать самолетов.

Сергей Галицкий
цитата по Sports.ru
Готовы выбрать победителя премии «Экспортер года eBay — 2021»?
Опасность участия в IPO

Обычно, когда говорят про риски участия в IPO рассказывают о потенциальных проблемах, связанных с низкой ликвидностью выходящих компаний и, как следствие, повышенной волатильностью. Я хочу рассказать про риск брокера, который часто не учитывается.

null