En este capítulo vamos a seguir avanzando en nuestras habilidades para la creación de documentos en formato docx. El resto de capítulos del tutorial los puedes ver aquí.
Para seguir avanzando vamos a añadir nuevas cosas al documento además de párrafos.
Comenzamos, como siempre, importando algunas cosas:
1 2 3 4 5 |
import random import string from urllib.request import urlretrieve from docx import Document |
Ya vimos como podíamos añadir párrafos usando el método add_paragraph
:
1 2 |
doc = Document() p = doc.add_paragraph("Este es nuestro primer párrafo") |
Añadiendo imágenes
En este momento, cuando hablo de añadir imágenes, me refiero a las imágenes típicas que suele haber en un documento que están separadas de otros párrafos.
Primero de todo vamos a descargar una imagen de internet, el logo de pybonacci, para poder usarla:
1 2 3 4 |
urlretrieve( "https://pybonacci.org/wp-content/uploads/2019/10/pybofractal1.png", filename="pybofractal.png" ) |
Añadimos ahora la nueva imagen usando el método add_picture
:
1 |
par_im = doc.add_picture("pybofractal.png") |
Guardamos el documento y lo visualizamos usando un procesador de texto:
1 |
doc.save("new.docx") |
Deberíamos de ver algo parecido a lo siguiente:

Vamos a ver todo lo que proporciona lo que acabamos de usar para añadir la imagen:
1 |
print(dir(par_im)) |
Nos mostrará algo parecido a lo siguiente:
1 2 3 4 5 6 7 |
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_inline', 'height', 'type', 'width'] |
Dispone de pocas cosas que podamos toquetear. Nos permite leer o definir el ancho y/o alto de la figura.
Si miramos el tipo:
1 |
print(type(par_im)) |
Vemos que el tipo se llama InlineShape
. Una traducción literal sería algo como ‘Forma entre lineas’. En procesadores de texto como Libreoffice o Microsoft Word tenemos dos capas de información, una capa de texto, que es lo que hemos estado usando hasta ahora, y una capa de dibujo. Esta segunda no la vamos a poder manejar con las versiones de python-docx
disponibles en este momento. La segunda capa la podemos ver como una capa donde podemos añadir imágenes flotantes en posiciones arbitrarias.
Un ejemplo hecho a mano en Libreoffice usando el documento que acabamos de crear, al cual le hemos añadido una forma flotante usando la capa de dibujo, podría ser algo como lo siguiente:

Puedes leer un poco más sobre esto de la capa de dibujo y las formas flotantes aquí.
Añadiendo encabezados/títulos
Todo documento que se precie tiene diferentes capítulos, partes, contenidos,… Para separarlos podemos usar encabezados o titulos para esas diferentes partes.
El objeto Document
tiene un método que se llama add_heading
(no confundir con header que ya vimos anteriormente en capítulos previos de este tutorial).
Vamos a usar ese método:
1 2 3 |
h0 = doc.add_heading(f"Encabezado tamaño 0", level=0) for i in range(1, 10): h = doc.add_heading(f"Encabezado tamaño {i}", level=i) |
Como véis, el método acepta un texto, que será el texto para el encabezado, y un nivel, que indicará el tamaño del encabezado siendo 0
para un título y valores de 1
a 9
siendo 1
el encabezado de mayor tamaño y 9
el encabezado de menor tamaño.
Si guardamos el documento nuevamente y lo visualizamos en un procesador de texto:
1 |
doc.save("new.docx") |
Veremos algo como lo siguiente:

Si miramos el tipo:
1 2 |
print(type(h0)) # del título, level=0 print(type(h)) # de un encabezado, level=1..9 |
Lo anterior mostrará:
1 2 |
<class 'docx.text.paragraph.Paragraph'> <class 'docx.text.paragraph.Paragraph'> |
Vemos que es un Paragraph
. Si miramos un poco mas en detalle.
1 2 3 |
print(p.style) # primer párrafo que hemos creado print(h0.style) # Encabezado de nivel 0 o título print(h.style) # Encabezado de nivel 9 |
Lo anterior mostrará:
1 2 3 |
_ParagraphStyle('Normal') id: 140504633096080 _ParagraphStyle('Title') id: 140504890136016 _ParagraphStyle('Heading 9') id: 140504890135952 |
Vemos que son párrafos con estilos diferentes y por eso se ven de forma diferente. Entraremos más en detalle en los estilos más adelante.
Añadiendo saltos de página
Esto ya lo hemos usado anteriormente. Vamos a verlo de nuevo brevemente:
1 2 3 4 |
sl = doc.add_page_break() print(type(sl)) print(dir(sl)) repr(sl.text) |
Lo anterior nos mostrará:
1 2 3 4 5 6 7 8 9 10 11 |
<class 'docx.text.paragraph.Paragraph'> ['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_element', '_insert_paragraph_before', '_p', '_parent', 'add_run', 'alignment', 'clear', 'insert_paragraph_before', 'paragraph_format', 'part', 'runs', 'style', 'text'] "'\\n'" |
Vemos que su tipo es Paragraph
y que lo que contiene se representa como un salto de linea. Entre sus propiedades no vemos nada especial.
Me surge una pregunta. ¿Cómo sé que estoy ante un salto de página? De momento, desde la propia biblioteca parece complicado y hay que ensuciarse las manos.
Añadiendo tablas
También se pueden añadir tablas de forma sencilla usando el método add_table
. Sigamos con nuestros ejemplos:
1 2 |
t = doc.add_table(3, 2) print(type(t)) |
Lo anterior mostrará:
1 |
<class 'docx.table.Table'> |
Vemos que es un objeto del tipo Table
. Veamos lo que nos ofrece este nuevo objeto:
1 |
print(dir(t)) |
Lo anterior nos mostrará lo siguiente en pantalla:
1 2 3 4 5 6 7 8 9 |
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_cells', '_column_count', '_element', '_parent', '_tbl', '_tblPr', 'add_column', 'add_row', 'alignment', 'autofit', 'cell', 'column_cells', 'columns', 'part', 'row_cells', 'rows', 'style', 'table', 'table_direction'] |
Podríamos rellenar las tablas de varias formas. Yo voy a usar una. Vosotros podéis ser imaginativos y probar otras diferentes:
1 2 3 |
for icol, col in enumerate(t.columns): for jcell, cell in enumerate(col.cells): cell.text = f"Celda ({jcell}, {icol})" |
Si ahora guardamos el documento de nuevo:
1 |
doc.save("new.docx") |
Deberiamos ver algo como lo siguiente:

Fin, de momento.
Ya has visto como meter contenido de distintas formas en el documento. Todavía es muy primitivo lo que estamos haciendo. Nos quedan ver unas cuantas cosas como formatear nuestro texto, añadir nuevas secciones, darle formato al documento,… Seguimos en el próximo.
hOLA
quiero saber como crear un documento word con el membrete de una empresa en pyhton ,agradeceria la informacion
Aquí se indica cómo meter imágenes inline con el texto: https://pybonacci.org/2020/06/23/escribiendo-ficheros-docx-de-word-con-python-capitulo-v-y-mas-texto/
Puedes probar usando eso en el header.