Время на прочтение
2 мин
Количество просмотров 70K
Исполняем обязанности по получению сведений о своих бенефициарных владельцах
Небольшая вводная
Начиная с 21 декабря 2016 года вступили изменения в ФЗ РФ «О противодействии легализации (отмыванию) доходов, полученных преступным путем, и финансированию терроризма», касательно обязанности юридического лица по раскрытию информации о своих бенефициарных владельцах. В связи с этим, многие компании направляют запросы по цепочке владения с целью выяснения своих бенефициарных владельцев. Кто-то формирует запросы на бумаге, кто-то рассылает электронные письма.
На наш взгляд, надлежащим доказательством исполнения обязанности «знай своего бенефициарного владельца» является наличие письма на бумаге с отметкой об отправке/вручении. Данные письма в идеале должны готовиться не реже одного раза в год. Если в ведении юриста находится всего несколько компаний, то составление писем не составляет особого труда. Но, если компаний больше 3-х десятков, составление писем превращается в уничтожающую позитив рутину. Дело усугубляется тем, что реквизиты писем постоянно меняются: подписанты увольняются, компании перерегистрируются, меняя адреса. Все это надо учитывать. Как здесь могут помочь навыки программирования на python?
Очень просто — хорошо бы иметь программу, которая сама будет подставлять в письма необходимые реквизиты. В том числе формировать сами письма, не заставляя создавать документ за документом вручную. Попробуем.
Структура письма в word. Модуль python docxtpl
Перед написанием кода программы посмотрим как должен выглядеть шаблон письма, в который мы будем помещать наши данные.
Текст письма от общества своему участнику/акционеру будет примерно следующим:
Напишем простую программу, которая заполнит для начала одно поле в нашем шаблоне, чтобы понять принцип работы.
Для начала в самом шаблоне письма Word вместо одного из полей, например, подписанта поставим переменную. Данная переменная должна быть на либо на англ. языке, либо на русском, но в одно слово.Также переменная должна быть обязательно заключена в двойные фигурные скобки. Выглядеть это будет примерно так:
Сама программа будет иметь следующий вид:
from docxtpl import DocxTemplate
doc = DocxTemplate("шаблон.docx")
context = { 'director' : "И.И.Иванов"}
doc.render(context)
doc.save("шаблон-final.docx")
Вначале мы импортируем модуль для работы с документами формата Word. Далее мы открываем шаблон, и в поле директор, которое бы обозначили ранее в самом шаблоне, вносим ФИО директора. В конце документ сохраняется под новым именем.
Таким образом, чтобы заполнить все поля в файле-шаблоне Word нам для начала необходимо определить все поля ввода в самом шаблоне скобками {} вместе с переменными и потом написать программу. Код будет примерно следующим:
from docxtpl import DocxTemplate
doc = DocxTemplate("шаблон.docx")
context = { 'emitent' : 'ООО Ромашка', 'address1' : 'г. Москва, ул. Долгоруковская, д. 0', 'участник': 'ООО Участник', 'адрес_участника': 'г. Москва, ул. Полевая, д. 0', 'director': 'И.И. Иванов'}
doc.render(context)
doc.save("шаблон-final.docx")
На выходе при исполнении программы мы получим готовый заполненный документ.
Скачать готовый шаблон Word можно здесь.
Как распечатать документ docx, odt в Python3. Максимум, что нашел как распечатать txt.
Принтер pos-58 для чеков, система ubuntu 18.04, python3. Есть два файла txt и docx, с первым всё в порядке, а на втором выскакивает ошибка, что-то вроде не поддерживаемый формат. Из Libre печатает. Как на Python3 реализовать?
insolor
45.2k15 золотых знаков54 серебряных знака94 бронзовых знака
задан 8 окт 2019 в 2:32
4
Можно вызвать Libreофис перегнать файл в pdf или ps которые понимает cups и отдать на печать. Вызови это через subprocess
unoconv --stdout filename.doc | lpr -P the_printer_name
или
libreoffice --pt the_printer_name --headless filename.odt
https://superuser.com/a/486150/239779
ответ дан 23 мая 2022 в 9:19
erieri
31.5k2 золотых знака26 серебряных знаков55 бронзовых знаков
Попробуйте извлечь текст из .docx файла и потом разпечатать его так же как .txt:
import docx
def extractText(filename):
doc = docx.Document('путь_к_файлу')
text = []
for paragraph in doc.paragraphs:
text.append(paragraph.text)
return 'n'.join(text)
ответ дан 9 дек 2019 в 23:05
Для тех, кому вдруг нужно будет, эта функция отправит документ на печать на основной принтер
import win32api
import win32print
def print_doc(filepath, filename):
f = '"' + filepath + filename + '"'
win32api.ShellExecute(0, "printto", f, '"%s"' % win32print.GetDefaultPrinter(), ".", 0)
ответ дан 23 мая 2021 в 3:58
1
Quickstart
To install using pip:
or using conda:
conda install docxtpl --channel conda-forge
Usage:
from docxtpl import DocxTemplate doc = DocxTemplate("my_word_template.docx") context = { 'company_name' : "World company" } doc.render(context) doc.save("generated_doc.docx")
Introduction¶
This package uses 2 major packages :
- python-docx for reading, writing and creating sub documents
- jinja2 for managing tags inserted into the template docx
python-docx-template has been created because python-docx is powerful for creating documents but not for modifying them.
The idea is to begin to create an example of the document you want to generate with microsoft word, it can be as complex as you want :
pictures, index tables, footer, header, variables, anything you can do with word.
Then, as you are still editing the document with microsoft word, you insert jinja2-like tags directly in the document.
You save the document as a .docx file (xml format) : it will be your .docx template file.
Now you can use python-docx-template to generate as many word documents you want from this .docx template and context variables you will associate.
Jinja2-like syntax¶
As the Jinja2 package is used, one can use all jinja2 tags and filters inside the word document.
Nevertheless there are some restrictions and extensions to make it work inside a word document:
Restrictions¶
The usual jinja2 tags, are only to be used inside the same run of a same paragraph, it can not be used across several paragraphs, table rows, runs.
If you want to manage paragraphs, table rows and a whole run with its style, you must use special tag syntax as explained in next chapter.
Note:
a ‘run’ for Microsoft Word is a sequence of characters with the same style.
For example, if you create a paragraph with all characters of the same style,
MS Word will create internally only one ‘run’ in the paragraph. Now,
if you put in bold a text in the middle of this paragraph,
word will transform the previous ‘run’ into 3 different ‘runs’ (normal — bold — normal).
Extensions¶
Display variables¶
As part of jinja2, one can used double braces:
if <var>
is a string, n
, a
, t
and f
will be translated respectively into newlines, new paragraphs, tabs and page breaks
But if <var>
is a RichText object, you must specify that you are changing the actual ‘run’:
Note the r
right after the opening braces.
VERY IMPORTANT : Variables must not contains characters like <
, >
and &
unless using Escaping
IMPORTANT : Always put space after a starting var delimiter and a space before the ending one :
Avoid:
{{myvariable}} {{rmyrichtext}}
Use instead:
{{ myvariable }} {{r myrichtext }}
Split and merge text¶
- You can merge a jinja2 tag with previous line by using
{%-
- You can merge a jinja2 tag with next line by using
-%}
A text containing Jinja2 tags may be unreadable if too long:
My house is located {% if living_in_town %} in urban area {% else %} in countryside {% endif %} and I love it.
One can use ENTER or SHIFT+ENTER to split a text like below, then use {%-
and -%}
to tell docxtpl to merge the whole thing:
My house is located {%- if living_in_town -%} in urban area {%- else -%} in countryside {%- endif -%} and I love it.
IMPORTANT : Use an unbreakable space (CTRL+SHIFT+SPACE) when a space is wanted at line beginning or ending.
IMPORTANT 2 : {%- xxx -%}
tags must be alone in a line : do not add some text before or after on the same line.
Escaping delimiters¶
In order to display {%
, %}
, {{
or }}
, one can use:
Tables¶
Spanning¶
You can span table cells horizontally in two ways, by using colspan
tag (see tests/dynamic_table.py):
<var> must contain an integer for the number of columns to span. See tests/test_files/dynamic_table.py for an example.
You can also span horizontally within a for loop (see tests/horizontal_merge.py):
You can also merge cells vertically within a for loop (see tests/vertical_merge.py):
Cell color¶
There is a special case when you want to change the background color of a table cell, you must put the following tag at the very beginning of the cell:
<var> must contain the color’s hexadecimal code without the hash sign
RichText¶
When you use {{ <var> }}
tag in your template, it will be replaced by the string contained within var variable.
BUT it will keep the current style.
If you want to add dynamically changeable style, you have to use both : the {{r <var> }}
tag AND a RichText
object within var variable.
You can change color, bold, italic, size, font and so on, but the best way is to use Microsoft Word to define your own character style
( Home tab -> modify style -> manage style button -> New style, select ‘Character style’ in the form ), see example in tests/richtext.py
Instead of using RichText()
, one can use its shortcut : R()
The RichText()
or R()
offers newline, new paragraph, and page break features : just use n
, a
, t
or f
in the
text, they will be converted accordingly.
There is a specific case for font: if your font is not displayed correctly, it may be because it is defined
only for a region. To know your region, it requires a little work by analyzing the document.xml inside the docx template (this is a zip file).
To specify a region, you have to prefix your font name this that region and a column:
ch = RichText('测试TEST', font='eastAsia:微软雅黑')
Important : When you use {{r }}
it removes the current character styling from your docx template, this means that if
you do not specify a style in RichText()
, the style will go back to a microsoft word default style.
This will affect only character styles, not the paragraph styles (MSWord manages this 2 kind of styles).
IMPORTANT : Do not use 2 times {{r
in the same run. Use RichText.add()
method to concatenate several strings and styles at python side and only one
{{r
at template side.
Important : RichText
objects are rendered into xml before any filter is applied
thus RichText
are not compatible with Jinja2 filters. You cannot write in your template something like {{r <var>|lower }}
.
Only solution is instead to do any filtering into your python code when creating the RichText
object.
Hyperlink with RichText¶
You can add an hyperlink to a text by using a Richtext with this syntax:
tpl=DocxTemplate('your_template.docx') rt = RichText('You can add an hyperlink, here to ') rt.add('google',url_id=tpl.build_url_id('http://google.com'))
Put rt
in your context, then use {{r rt}}
in your template
Inline image¶
You can dynamically add one or many images into your document (tested with JPEG and PNG files).
just add {{ <var> }}
tag in your template where <var>
is an instance of doxtpl.InlineImage:
myimage = InlineImage(tpl, image_descriptor='test_files/python_logo.png', width=Mm(20), height=Mm(10))
You just have to specify the template object, the image file path and optionally width and/or height.
For height and width you have to use millimeters (Mm), inches (Inches) or points(Pt) class.
Please see tests/inline_image.py for an example.
Sub-documents¶
A template variable can contain a complex subdoc object and be built from scratch using python-docx document methods.
To do so, first, get the sub-document object from your template object, then use it by treating it as a python-docx document object.
See example in tests/subdoc.py.
Since docxtpl V0.12.0, it is now possible to merge an existing .docx as a subdoc, just specify its path when
calling method new_subdoc()
tpl = DocxTemplate('templates/merge_docx_master_tpl.docx') sd = tpl.new_subdoc('templates/merge_docx_subdoc.docx')
See tests/merge_docx.py for full code.
Escaping¶
By default, no escaping is done : read carefully this chapter if you want to avoid crashes during docx generation.
When you use a {{ <var> }}
, under the hood, you are modifying an XML word document, this means you cannot use all chars,
especially <
, >
and &
. In order to use them, you must escape them. There are 4 ways :
context = { 'var':R('my text') }
and{{r <var> }}
in the template (note ther
),context = { 'var':'my text'}
and{{ <var>|e }}
in your word templatecontext = { 'var':escape('my text')}
and{{ <var> }}
in the template.- enable autoescaping when calling render method:
tpl.render(context, autoescape=True)
(default is autoescape=False)
See tests/escape.py example for more informations.
Another solution, if you want to include a listing into your document, that is to escape the text and manage n
, a
, and f
you can use the Listing
class :
in your python code:
context = { 'mylisting':Listing('the listingnwithnsomenlines a and some paragraph a and special chars : <>&') }
in your docx template just use {{ mylisting }}
With Listing()
, you will keep the current character styling (except after a a
as you start a new paragraph).
Replace docx pictures¶
It is not possible to dynamically add images in header/footer, but you can change them.
The idea is to put a dummy picture in your template, render the template as usual, then replace the dummy picture with another one.
You can do that for all medias at the same time.
Note: the aspect ratio will be the same as the replaced image
Note2 : Specify the filename that has been used to insert the image in the docx template (only its basename, not the full path)
Syntax to replace dummy_header_pic.jpg:
tpl.replace_pic('dummy_header_pic.jpg','header_pic_i_want.jpg')
The replacement occurs in headers, footers and the whole document’s body.
Replace embedded objects¶
It works like medias replacement, except it is for embedded objects like embedded docx.
Syntax to replace embedded_dummy.docx:
tpl.replace_embedded('embedded_dummy.docx','embedded_docx_i_want.docx')
WARNING : unlike replace_pic() method, embedded_dummy.docx MUST exist in the template directory when rendering and saving the generated docx. It must be the same
file as the one inserted manually in the docx template.
The replacement occurs in headers, footers and the whole document’s body.
Note that replace_embedded() may not work on other documents than embedded docx.
Instead, you should use zipname replacement:
tpl.replace_zipname( 'word/embeddings/Feuille_Microsoft_Office_Excel1.xlsx', 'my_excel_file.xlsx')
The zipname is the one you can find when you open docx with WinZip, 7zip (Windows) or unzip -l (Linux).
The zipname starts with “word/embeddings/”. Note that the file to be replaced is renamed by MSWord, so you have to guess a little bit…
This works for embedded MSWord file like Excel or PowerPoint file, but won’t work for others like PDF, Python or even Text files :
For these ones, MSWord generate an oleObjectNNN.bin file which is no use to be replaced as it is encoded.
Get Defined Variables¶
In order to get the missing variables after rendering use
tpl=DocxTemplate('your_template.docx') tpl.render(context_dict) set_of_variables = tpl.get_undeclared_template_variables()
IMPORTANT : You may use the method before rendering to get a set of keys you need, e.g. to be prompted to a user or written in a file for manual processing.
Multiple rendering¶
Since v0.15.0, it is possible to create DocxTemplate
object once and call
render(context)
several times. Note that if you want to use replacement
methods like replace_media()
, replace_embedded()
and/or replace_zipname()
during multiple rendering, you will have to call reset_replacements()
at rendering loop start.
Microsoft Word 2016 special cases¶
MS Word 2016 will ignore t
tabulations. This is special to that version.
Libreoffice or Wordpad do not have this problem. The same thing occurs for line
beginning with a jinja2 tag providing spaces : They will be ignored.
To solve these problem, the solution is to use Richtext:
tpl.render({ 'test_space_r' : RichText(' '), 'test_tabs_r': RichText(5*'t'), })
And in your template, use the {{r notation:
{{r test_space_r}} Spaces will be preserved {{r test_tabs_r}} Tabs will be displayed
Jinja custom filters¶
render()
accepts jinja_env
optional argument : you may pass a jinja environment object.
By this way you will be able to add some custom jinja filters:
from docxtpl import DocxTemplate import jinja2 def multiply_by(value, by): return value * by doc = DocxTemplate("my_word_template.docx") context = { 'price_dollars' : 5.00 } jinja_env = jinja2.Environment() jinja_env.filters['multiply_by'] = multiply_by doc.render(context,jinja_env) doc.save("generated_doc.docx")
Then in your template, you will be able to use:
Euros price : {{ price_dollars|multiply_by(0.88) }}
Command-line execution¶
One can use docxtpl module directly on command line to generate a docx from a template and a json file as a context:
usage: python -m docxtpl [-h] [-o] [-q] template_path json_path output_filename Make docx file from existing template docx and json data. positional arguments: template_path The path to the template docx file. json_path The path to the json file with the data. output_filename The filename to save the generated docx. optional arguments: -h, --help show this help message and exit -o, --overwrite If output file already exists, overwrites without asking for confirmation -q, --quiet Do not display unnecessary messages
See tests/module_execute.py for an example.
Examples¶
The best way to see how it works is to read examples, they are located in tests/ directory.
Docx test templates are in tests/templates/. To generate final docx files:
cd tests/ python runtests.py
Generated files are located in tests/output directory.
If you are not sure about your python environment, python-docx-template provides Pipfiles
for that:
pip install pipenv (if not already done) cd python-docx-template (where Pipfiles are) pipenv install --python 3.6 -d pipenv shell cd tests/ python runtests.py
Модуль python-docx
предназначен для создания и обновления файлов с расширением .docx
— Microsoft Word. Этот модуль имеет одну зависимость: сторонний модуль lxml
.
Модуль python-docx
размещен на PyPI, поэтому установка относительно проста.
# создаем виртуальное окружение, если нет $ python3 -m venv .venv --prompt VirtualEnv # активируем виртуальное окружение $ source .venv/bin/activate # ставим модуль python-docx (VirtualEnv):~$ python3 -m pip install -U python-docx
Основы работы с файлами Microsoft Word на Python.
- Открытие/создание документа;
- Добавление заголовка документа;
- Добавление абзаца;
- Применение встроенного стиля в Microsoft Word к абзацу;
- Жирный, курсив и подчеркнутый текст в абзаце;
- Применение стилей Microsoft Word к символам текста (к прогону);
- Пользовательский стиль символов текста;
- Добавление разрыва страницы;
- Добавление картинки в документ;
- Чтение документов MS Word.
Открытие/создание документа.
Первое, что вам понадобится, это документ, над которым вы будете работать. Самый простой способ:
from docx import Document # создание документа document = Document() # открытие документа document = Document('/path/to/document.docx')
При этом создается пустой документ, основанный на «шаблоне» по умолчанию. Другими словами, происходит примерно то же самое, когда пользователь нажимает на иконку в Microsoft Word «Новый документ» с использованием встроенных значений по умолчанию.
При этом шрифт документа и его размер по умолчанию для всего документа можно задать следующим образом:
from docx import Document from docx.shared import Pt doc = Document() # задаем стиль текста по умолчанию style = doc.styles['Normal'] # название шрифта style.font.name = 'Arial' # размер шрифта style.font.size = Pt(14) document.add_paragraph('Текст документа')
Так же, можно открывать существующий документ Word и работать с ним при помощи модуля python-docx
. Для этого, в конструктор класса Document()
необходимо передать путь к существующему документу Microsoft Word.
Добавление заголовка документа.
В любом документе, основной текст делится на разделы, каждый из которых начинается с заголовка. Название таких разделов можно добавить методом Document.add_heading()
:
# без указания аргумента `level` # добавляется заголовок "Heading 1" head = document.add_heading('Основы работы с файлами Microsoft Word на Python.') from docx.enum.text import WD_ALIGN_PARAGRAPH # выравнивание посередине head.alignment = WD_ALIGN_PARAGRAPH.CENTER
По умолчанию, добавляется заголовок верхнего уровня, который отображается в Word как «Heading 1». Если нужен заголовок для подраздела, то просто указываем желаемый уровень в виде целого числа от 1 до 9:
document.add_heading('Добавление заголовка документа', level=2)
Если указать level=0
, то будет добавлен текст с встроенным стилем титульной страницы. Такой стиль может быть полезен для заголовка относительно короткого документа без отдельной титульной страницы.
Так же, заголовки разделов можно добавлять методом document.add_paragraph().add_run()
, с указанным размером шрифта.
Например:
from docx import Document from docx.shared import Pt doc = Document() # добавляем текст прогоном run = doc.add_paragraph().add_run('Заголовок, размером 24 pt.') # размер шрифта run.font.size = Pt(24) run.bold = True doc.save('test.docx')
Добавление абзаца.
Абзацы в Word имеют основополагающее значение. Они используются для добавления колонтитулов, основного текста, заголовков, элементов списков, картинок и т.д.
Смотрим самый простой способ добавить абзац/параграф:
p = document.add_paragraph('Абзацы в Word имеют основополагающее значение.')
Метод Document.add_paragraph()
возвращает ссылку на только что добавленный абзац (объект Paragraph
). Абзац добавляется в конец документа. Эту ссылку можно использовать в качестве своеобразного «курсора» и например, вставить новый абзац прямо над ним:
prior_p = p.insert_paragraph_before( 'Объект `paragraph` - это ссылка на только что добавленный абзац.')
Такое поведение позволяет вставить абзац в середину документа, это важно при изменении существующего документа, а не при его создании с нуля.
Ссылка на абзац, так же используется для его форматирования встроенными в MS Word стилями или для кастомного/пользовательского форматирования.
Пользовательское форматирование абзаца.
Форматирование абзацев происходит при помощи объекта ParagraphFormat
.
Простой способ форматировать абзац/параграф:
from docx import Document from docx.shared import Mm from docx.enum.text import WD_ALIGN_PARAGRAPH doc = Document() # Добавляем абзац p = doc.add_paragraph('Новый абзац с отступами и красной строкой.') # выравниваем текст абзаца p.alignment = WD_ALIGN_PARAGRAPH.JUSTIFY # получаем объект форматирования fmt = p.paragraph_format # Форматируем: # добавляем отступ слева fmt.first_line_indent = Mm(15) # добавляем отступ до fmt.space_before = Mm(20) # добавляем отступ слева fmt.space_after = Mm(10) doc.add_paragraph('Новый абзац.') doc.add_paragraph('Еще новый абзац.') doc.save('test.docx')
Чтобы узнать, какие параметры абзаца еще можно настроить/изменить, смотрите материал «Объект ParagraphFormat
»
Очень часто в коде, с возвращенной ссылкой (в данном случае p
) ничего делать не надо, следовательно нет смысла ее присваивать переменной.
Применение встроенного стиля в Microsoft Word к абзацу.
Стиль абзаца — это набор правил форматирования, который заранее определен в Microsoft Word, и храниться в редакторе в качестве переменной. По сути, стиль позволяет сразу применить к абзацу целый набор параметров форматирования.
Можно применить стиль абзаца, прямо при его создании:
document.add_paragraph('Стиль абзаца как цитата', style='Intense Quote') document.add_paragraph('Стиль абзаца как список.', style='List Bullet')
В конкретном стиле 'List Bullet'
, абзац отображается в виде маркера. Также можно применить стиль позже. Две строки, в коде ниже, эквивалентны примеру выше:
document.add_paragraph('Другой стиль абзаца.').style = 'List Number' # Эквивалентно paragraph = document.add_paragraph('Другой стиль абзаца.') # применяем стиль позже paragraph.style = 'List Number'
Стиль указывается с использованием его имени, в этом примере имя стиля — 'List'
. Как правило, имя стиля точно такое, как оно отображается в пользовательском интерфейсе Word.
Обратите внимание, что можно установить встроенный стиль прямо на результат document.add_paragraph()
, без использования возвращаемого объекта paragraph
Жирный, курсив и подчеркнутый текст в абзаце.
Разберемся, что происходит внутри абзаца:
- Абзац содержит все форматирование на уровне блока, такое как — отступ, высота строки, табуляции и так далее.
- Форматирование на уровне символов, например полужирный и курсив, применяется на уровне прогона
paragraph.add_run()
. Все содержимое абзаца должно находиться в пределах цикла, но их может быть больше одного. Таким образом, для абзаца с полужирным словом посередине требуется три прогона: обычный, полужирный — содержащий слово, и еще один нормальный для текста после него.
Когда создается абзац методом Document.add_paragraph()
, то передаваемый текст добавляется за один прогон Run
. Пустой абзац/параграф можно создать, вызвав этот метод без аргументов. В этом случае, наполнить абзац текстом можно с помощью метода Paragraph.add_run()
. Метод абзаца .add_run()
можно вызывать несколько раз, тем самым добавляя информацию в конец данного абзаца:
paragraph = document.add_paragraph('Абзац содержит форматирование ') paragraph.add_run('на уровне блока.')
В результате получается абзац, который выглядит так же, как абзац, созданный из одной строки. Если не смотреть на полученный XML, то не очевидно, где текст абзаца разбивается на части. Обратите внимание на конечный пробел в конце первой строки. Необходимо четко указывать, где появляются пробелы в начале и в конце прогона, иначе текст будет слитный (без пробелов). Они (пробелы) автоматически не вставляются между прогонами paragraph.add_run()
. Метод paragraph.add_run()
возвращает ссылку на объект прогона Run
, которую можно использовать, если она нужна.
Объекты прогонов имеют следующие свойства, которые позволяют установить соответствующий стиль:
.bold
: полужирный текст;.underline
: подчеркнутый текст;.italic
: курсивный (наклонный) текст;.strike
: зачеркнутый текст.
paragraph = document.add_paragraph('Абзац содержит ') paragraph.add_run('форматирование').bold = True paragraph.add_run(' на уровне блока.')
Получится текст, что то вроде этого: «Абзац содержит форматирование на уровне блока».
Обратите внимание, что можно установить полужирный или курсив прямо на результат paragraph.add_run()
, без использования возвращаемого объекта прогона:
paragraph.add_run('форматирование').bold = True # или run = paragraph.add_run('форматирование') run.bold = True
Передавать текст в метод Document.add_paragraph()
не обязательно. Это может упростить код, если строить абзац из прогонов:
paragraph = document.add_paragraph() paragraph.add_run('Абзац содержит ') paragraph.add_run('форматирование').bold = True paragraph.add_run(' на уровне блока.')
Пользовательское задание шрифта прогона.
from docx import Document from docx.shared import Pt, RGBColor # создание документа doc = Document() # добавляем текст прогоном run = doc.add_paragraph().add_run('Заголовок, размером 24 pt.') # название шрифта run.font.name = 'Arial' # размер шрифта run.font.size = Pt(24) # цвет текста run.font.color.rgb = RGBColor(0, 0, 255) # + жирный и подчеркнутый run.font.bold = True run.font.underline = True doc.save('test.docx')
Применение стилей Microsoft Word к символам текста (к прогону).
В дополнение к встроенным стилям абзаца, которые определяют группу параметров уровня абзаца, Microsoft Word имеет стили символов, которые определяют группу параметров уровня прогона paragraph.add_run()
. Другими словами, можно думать о стиле текста как об указании шрифта, включая его имя, размер, цвет, полужирный, курсив и т. д.
Подобно стилям абзацев, стиль символов текста будет определен в документе, который открывается с помощью вызова Document()
(см. Общие сведения о стилях).
Стиль символов можно указать при добавлении нового прогона:
paragraph = document.add_paragraph('Обычный текст, ') paragraph.add_run('текст с акцентом.', 'Emphasis')
Также можете применить стиль к прогону после его добавления. Этот код дает тот же результат, что и строки выше:
paragraph = document.add_paragraph() paragraph.add_run('Обычный текст, ') paragraph.add_run('текст с акцентом.').style = 'Emphasis'
Как и в случае со стилем абзаца, имя стиля текста такое, как оно отображается в пользовательском интерфейсе Word.
Пользовательский стиль символов текста.
from docx import Document from docx.shared import Pt, RGBColor # создание документа doc = Document() # задаем стиль текста по умолчанию style = doc.styles['Normal'] # название шрифта style.font.name = 'Calibri' # размер шрифта style.font.size = Pt(14) p = doc.add_paragraph('Пользовательское ') # добавляем текст прогоном run = p.add_run('форматирование ') # размер шрифта run.font.size = Pt(16) # курсив run.font.italic = True # добавляем еще текст прогоном run = p.add_run('символов текста.') # Форматируем: # название шрифта run.font.name = 'Arial' # размер шрифта run.font.size = Pt(18) # цвет текста run.font.color.rgb = RGBColor(255, 0, 0) # + жирный и подчеркнутый run.font.bold = True run.font.underline = True doc.save('test.docx')
Добавление разрыва страницы.
При создании документа, время от времени нужно, чтобы следующий текст выводился на отдельной странице, даже если последняя не заполнена. Жесткий разрыв страницы можно сделать следующим образом:
document.add_page_break()
Если вы обнаружите, что используете это очень часто, это, вероятно, знак того, что вы могли бы извлечь выгоду, лучше разбираясь в стилях абзацев. Одно свойство стиля абзаца, которое вы можете установить, — это разрыв страницы непосредственно перед каждым абзацем, имеющим этот стиль. Таким образом, вы можете установить заголовки определенного уровня, чтобы всегда начинать новую страницу. Подробнее о стилях позже. Они оказываются критически важными для получения максимальной отдачи от Word.
Жесткий разрыв страницы можно привязать к стилю абзаца, и затем применять его для определенных абзацев, которые должны начинаться с новой страницы. Так же можно установить жесткий разрыв на стиль заголовка определенного уровня, чтобы с него всегда начинать новую страницу. В общем, стили, оказываются критически важными для того, чтобы получить максимальную отдачу от модуля python-docx
.
Добавление картинки в документ.
Microsoft Word позволяет разместить изображение в документе с помощью пункта меню «Вставить изображение«. Вот как это сделать при помощи модуля python-docx
:
document.add_picture('/path/to/image-filename.png')
В этом примере используется путь, по которому файл изображения загружается из локальной файловой системы. В качестве пути можно использовать файловый объект, по сути, любой объект, который действует как открытый файл. Такое поведение может быть полезно, если изображение извлекается из базы данных или передается по сети.
Размер изображения.
По умолчанию, изображение добавляется с исходными размерами, что часто не устраивает пользователя. Собственный размер рассчитывается как px/dpi
. Таким образом, изображение размером 300×300 пикселей с разрешением 300 точек на дюйм появляется в квадрате размером один дюйм. Проблема в том, что большинство изображений не содержат свойства dpi
, и по умолчанию оно равно 72 dpi. Следовательно, то же изображение будет иметь одну сторону, размером 4,167 дюйма, что означает половину страницы.
Чтобы получить изображение нужного размера, необходимо указывать его ширину или высоту в удобных единицах измерения, например, в миллиметрах или сантиметрах:
from docx.shared import Mm document.add_picture('/path/to/image-filename.png', width=Mm(35))
Если указать только одну из сторон, то модуль python-docx
использует его для вычисления правильно масштабированного значения другой стороны изображения. Таким образом сохраняется соотношение сторон и изображение не выглядит растянутым.
Классы Mm()
и Cm()
предназначены для того, чтобы можно было указывать размеры в удобных единицах. Внутри python-docx
используются английские метрические единицы, 914400 дюймов. Так что, если просто указать размер, что-то вроде width=2
, то получится очень маленькое изображение. Классы Mm()
и Cm()
импортируются из подпакета docx.shared
. Эти классы можно использовать в арифметике, как если бы они были целыми числами. Так что выражение, width=Mm(38)/thing_count, работает нормально.
Чтение документов Microsoft Word.
В модуле python-docx
, структура документа Microsoft Word представлена тремя различными типами данных. На самом верхнем уровне объект Document()
представляет собой весь документ. Объект Document()
содержит список объектов Paragraph()
, которые представляют собой абзацы документа. Каждый из абзацев содержит список, состоящий из одного или нескольких объектов Run()
, представляющих собой фрагменты текста с различными стилями форматирования.
Например:
>>> from docx import Document >>> doc = Document('/path/to/example.docx') # количество абзацев в документе >>> len(doc.paragraphs) # текст первого абзаца в документе >>> doc.paragraphs[0].text # текст второго абзаца в документе >>> doc.paragraphs[1].text # текст первого прогона второго абзаца >>> doc.paragraphs[1].runs[0].text
Используя следующий код, можно получить весь текст документа:
text = [] for paragraph in doc.paragraphs: text.append(paragraph.text) print('nn'.join(text))
А так можно получить стили всех параграфов:
styles = [] for paragraph in doc.paragraphs: styles.append(paragraph.style)
Использовать полученные стили можно следующим образом:
# изменим стиль 1 параграфа на # стиль взятый из 3 параграфа doc.paragraphs[0].style = styles[2]
This should work:
subprocess.Popen(["C:\Program FilesMicrosoft OfficeOffice12winword.exe", "P:\docs\daily checks.doc", "/mFilePrintDefault", "/mFileExit"]).communicate()
Or, altenatively,
subprocess.Popen("'C:\Program FilesMicrosoft OfficeOffice12winword.exe' 'P:\docs\daily checks.doc' /mFilePrintDefault /mFileExit", shell=True).communicate()
When you use shell=True
the command is executed through a shell. This means that you have to pass a single string the same way as you would write the command in a shell, that is, with the quotes to prevent arguments with spaces to be splitted.
When you use shell=False
(the default value), the command isn’t executed through a shell. This means that you’ve to split the arguments yourself. The way you do this, is passing a list with all the arguments. In this case, no extra quoting is needed because the list elements already provide this information.