---
title: "Python e Word com python-docx: Criar e Editar Documentos"
url: "https://python.dev.br/blog/python-e-word-python-docx/"
markdown_url: "https://python.dev.br/blog/python-e-word-python-docx.MD"
description: "Aprenda a criar e editar documentos Word (.docx) em Python com a biblioteca python-docx: parágrafos, formatação, tabelas, imagens, cabeçalho e rodapé, e geração de contratos e propostas em lote a partir de um template. Guia prático em português."
date: "2026-07-06"
author: "Equipe Python Brasil"
---

# Python e Word com python-docx: Criar e Editar Documentos

Aprenda a criar e editar documentos Word (.docx) em Python com a biblioteca python-docx: parágrafos, formatação, tabelas, imagens, cabeçalho e rodapé, e geração de contratos e propostas em lote a partir de um template. Guia prático em português.


Gerar documentos do Word automaticamente é uma das automações de escritório que mais economizam tempo. Em vez de abrir o Word, copiar um modelo, trocar o nome do cliente, a data e o valor, e salvar como um novo arquivo, um script Python pode produzir dezenas de **contratos, propostas comerciais, certificados ou relatórios** em segundos — cada um personalizado, formatado e pronto para enviar. A biblioteca que faz isso é a `python-docx`, e neste tutorial você vai aprender a criar, editar e automatizar documentos `.docx` com exemplos práticos voltados para a realidade brasileira.

Se você já automatiza [planilhas Excel com Python](/blog/python-e-excel-openpyxl/) ou [gera relatórios em PDF](/blog/python-gerar-pdf-relatorios/), este artigo fecha o trio de automação de documentos mais pedido em escritórios, financeiras e consultorias. Para quem está começando, vale revisar o [guia de Python para iniciantes](/blog/python-para-iniciantes-guia-completo/) antes; aqui o foco é uma tarefa específica, mas recorrente.

## Instalação e primeiros passos

A `python-docx` é uma biblioteca de terceiros. Instale com o `pip` dentro do seu [ambiente virtual](/blog/virtual-environments-python/):

```bash
pip install python-docx
```

O pacote é importado como `docx`. O fluxo básico é sempre o mesmo: criar (ou abrir) um documento, adicionar conteúdo e salvar. Veja o "hello world" dos documentos Word:

```python
from docx import Document
from docx.shared import Pt

doc = Document()                       # documento novo e vazio
doc.add_heading("Proposta Comercial", level=1)
doc.add_paragraph("Prezado cliente, segue a nossa proposta para o projeto.")

doc.save("proposta.docx")              # grava o arquivo .docx
```

Ao rodar esse script, surge um arquivo `proposta.docx` válido, abrível no Word, no LibreOffice ou no Google Docs. **Nenhum Microsoft Word precisa estar instalado** — a biblioteca lê e escreve o XML interno do formato `.docx` diretamente, o que permite rodar até em servidor Linux.

## Parágrafos, títulos e formatação de texto

O conteúdo de um documento é organizado em parágrafos (`Paragraph`). Dentro de cada parágrafo, os trechos com formatação própria são chamados de *runs*. Para aplicar negrito, itálico, cor ou tamanho a apenas uma parte do texto, adicione um `run`:

```python
from docx import Document
from docx.shared import Pt, RGBColor

doc = Document()

p = doc.add_paragraph()
p.add_run("Valor total: ")                      # texto normal
valor = p.add_run("R$ 12.500,00")               # trecho destacado
valor.bold = True
valor.font.size = Pt(14)
valor.font.color.rgb = RGBColor(0x1F, 0x4E, 0x79)  # azul corporativo

# Títulos com níveis de 0 (Title) a 9
doc.add_heading("1. Escopo do serviço", level=2)
doc.add_heading("2. Cronograma", level=2)
```

A regra prática: forme o texto sempre pelos *runs*, nunca tente "misturar negrito" em um `add_paragraph("texto")` único. Um parágrafo pode ter quantos runs forem necessários, cada um com sua formatação.

## Fontes, tamanhos e estilo padrão

Para definir uma fonte e um tamanho padrão para o documento inteiro, altere o estilo `Normal`:

```python
from docx import Document
from docx.shared import Pt

doc = Document()
estilo = doc.styles["Normal"]
estilo.font.name = "Calibri"
estilo.font.size = Pt(11)

# Agora todo add_paragraph() usa Calibri 11 por padrão
doc.add_paragraph("Este texto segue o estilo Normal definido acima.")
```

Isso evita repetir a fonte em cada parágrafo. Para trocar a fonte de todo o documento de uma vez — útil ao padronizar relatórios com a identidade visual da empresa — mexer no estilo `Normal` é mais eficiente do que percorrer parágrafo por parágrafo.

## Listas com marcadores e numeradas

A `python-docx` cria listas aplicando estilos prontos. Não há método `add_list`; usamos `add_paragraph` com o estilo apropriado:

```python
doc.add_paragraph("Levantamento de requisitos", style="List Bullet")
doc.add_paragraph("Desenvolvimento", style="List Bullet")
doc.add_paragraph("Homologação e entrega", style="List Bullet")

doc.add_paragraph("Primeira parcela na assinatura", style="List Number")
doc.add_paragraph("Segunda parcela na entrega", style="List Number")
```

`List Bullet` gera a lista com marcadores; `List Number`, a lista numerada. Esses estilos existem no modelo padrão do Word; se você partir de um template próprio, confirme que os estilos de lista estão presentes nele.

## Tabelas

Tabelas são perfeitas para cronogramas, tabelas de preço e resumos financeiros. Crie com `add_table` e preencha célula a célula:

```python
from docx import Document

doc = Document()

dados = [
    ("Etapa", "Entrega", "Valor"),
    ("Descoberta", "Semana 2", "R$ 3.000,00"),
    ("Desenvolvimento", "Semana 6", "R$ 6.500,00"),
    ("Implantação", "Semana 8", "R$ 3.000,00"),
]

tabela = doc.add_table(rows=len(dados), cols=3)
tabela.style = "Light Grid Accent 1"   # estilo com bordas e cabeçalho

for i, linha in enumerate(dados):
    for j, valor in enumerate(linha):
        tabela.rows[i].cells[j].text = valor

# Negrito na linha de cabeçalho
for celula in tabela.rows[0].cells:
    for paragrafo in celula.paragraphs:
        for run in paragrafo.runs:
            run.bold = True
```

O estilo `"Light Grid Accent 1"` (e outros da família `Light Grid` / `Light List`) já vem com o Word e aplica bordas e cores. Preencher a tabela a partir de uma lista de dicionários — por exemplo, lida de uma planilha ou de um banco de dados — é o caminho natural para gerar relatórios dinâmicos.

## Inserindo imagens

Adicione logotipos, gráficos ou assinaturas digitalizadas com `add_picture`:

```python
from docx.shared import Cm

doc.add_picture("logo.png", width=Cm(5))
doc.add_paragraph()  # espaço após a imagem
```

Sempre defina `width` ou `height` para controlar o tamanho; sem isso, a imagem entra na resolução original, podendo ultrapassar a margem da página. Para imagens geradas dinamicamente — um gráfico do matplotlib, por exemplo — salve o PNG em disco com `plt.savefig()` e depois chame `add_picture`.

## Cabeçalho, rodapé e seções

Cada documento tem uma ou mais *seções* (`Section`), e cada seção traz seu próprio cabeçalho e rodapé. É neles que ficam logotipo, nome do documento e numeração:

```python
section = doc.sections[0]

# Cabeçalho
header = section.header
header.is_linked_to_previous = False
hp = header.paragraphs[0]
hp.text = "Minha Empresa Ltda. — CNPJ 00.000.000/0001-00"

# Rodapé
footer = section.footer
fp = footer.paragraphs[0]
fp.text = "Documento confidencial — Proposta Comercial"
```

Numeração automática de páginas exige inserir um campo de página no rodapé, o que é feito em nível de XML e sai do escopo deste tutorial. Para documentos que precisam desse recurso de forma confiável, o atalho mais produtivo é manter um template `.docx` já com o rodapé configurado e só preencher o conteúdo via script.

## Mini-projeto: gerando contratos a partir de um template

O uso mais valioso da biblioteca é transformar um modelo fixo em dezenas de documentos personalizados. A técnica é abrir o template, substituir marcadores e salvar cada cópia. Veja um gerador de **contratos de prestação de serviços**:

```python
from docx import Document
from datetime import date

clientes = [
    {"nome": "Ana Souza", "servico": "desenvolvimento de site", "valor": "R$ 8.000,00"},
    {"nome": "Bruno Lima", "servico": "integração de API", "valor": "R$ 4.500,00"},
    {"nome": "Carla Dias", "servico": "automação de relatórios", "valor": "R$ 3.200,00"},
}

hoje = date.today().strftime("%d/%m/%Y")

for cliente in clientes:
    doc = Document("template_contrato.docx")

    for paragrafo in doc.paragraphs:
        # Substitui cada marcador no texto do parágrafo
        texto = paragrafo.text
        texto = texto.replace("{{nome}}", cliente["nome"])
        texto = texto.replace("{{servico}}", cliente["servico"])
        texto = texto.replace("{{valor}}", cliente["valor"])
        texto = texto.replace("{{data}}", hoje)

        # Reescreve preservando o estilo do parágrafo
        for run in paragrafo.runs:
            run.text = ""
        if paragrafo.runs:
            paragrafo.runs[0].text = texto
        else:
            paragrafo.text = texto

    nome_arquivo = f"contrato_{cliente['nome'].split()[0].lower()}.docx"
    doc.save(nome_arquivo)
    print(f"Gerado: {nome_arquivo}")
```

O modelo `template_contrato.docx` contém texto normal com marcadores `{{nome}}`, `{{servico}}`, `{{valor}}` e `{{data}}`. O script gera três contratos prontos, cada um com seus dados. Para volumes maiores ou substituições que envolvam tabelas dinâmicas, a biblioteca `docxtpl` (que aplica a sintaxe Jinja2 sobre o `.docx`) é mais robusta e evita o trabalho manual de limpar runs.

> **Atenção ao detalhe dos runs:** quando você digita `{{nome}}` no Word, ele pode quebrar o texto em vários runs internos (por correção ortográfica, por exemplo). Por isso, ao montar o template, desligue a revisão ou digite os marcadores de uma vez; caso contrário, o `replace` pode não encontrar o trecho inteiro. A `docxtpl` lida com isso automaticamente.

## Lendo e editando documentos existentes

Abrir um `.docx` para extrair ou modificar conteúdo é igualmente simples:

```python
from docx import Document

doc = Document("relatorio.docx")

# Listar todos os parágrafos
for paragrafo in doc.paragraphs:
    if paragrafo.text.strip():
        print(paragrafo.text)

# Contar tabelas e ler a primeira
print(f"Total de tabelas: {len(doc.tables)}")
for linha in doc.tables[0].rows:
    print([celula.text for celula in linha.cells])
```

Essa leitura é a base de pipelines de extração de dados — por exemplo, varrer um diretório de [arquivos](/blog/manipulacao-de-arquivos-python/) `.docx` de notas fiscais ou contratos para alimentar uma planilha ou um banco de dados, sem depender de digitação manual.

## Boas práticas

- **Prefira templates a código para o layout.** Desenhar cabeçalhos complexos, margens e identidade visual pelo código é trabalhoso; faça isso uma vez no Word, salve como template `.docx` e use o script só para preencher.
- **Versione seus modelos.** Guarde `template_v1.docx`, `template_v2.docx` no repositório ao lado do script, para rastrear mudanças de layout.
- **Cuidado com runs quebrados.** Ao substituir texto em templates, lembre-se de que o Word divide palavras em vários runs; limpe os runs ou use a `docxtpl`.
- **Valide antes de enviar.** Em [automações](/blog/automatizacao-com-python/) que enviam o documento por e-mail, abra uma amostra para conferir antes do envio em massa.
- **Use try/except em operações de arquivo.** Envolver `doc.save()` e a leitura de templates em tratamento de erros evita que um arquivo travado interrompa um lote inteiro — veja as práticas do nosso guia de [tratamento de erros em Python](/blog/tratamento-de-erros-python/).

## Próximos passos

Para evoluir depois deste tutorial:

1. **Combine documentos e planilhas** — leia uma [planilha Excel](/blog/python-e-excel-openpyxl/) com a lista de clientes e gere um contrato `.docx` para cada linha.
2. **Exporte para PDF** — encadeie a geração do `.docx` com uma conversão para PDF quando o documento for assinado.
3. **Automatize o envio** — conecte a geração do documento ao [envio de e-mails com Python](/blog/python-para-automacao-de-emails/) para entregar propostas e contratos sem toque manual.

Automatizar a geração de documentos Word troca uma tarefa repetitiva e propensa a erros de digitação por um script de poucas linhas. Comece com um template simples, valide o resultado e expanda para listas, tabelas e geração em lote. Para acompanhar as oportunidades do mercado de desenvolvimento Python no Brasil, confira nossas [vagas de Python](/vagas/) e o [guia de primeiro emprego como programador Python](/carreira/primeiro-emprego-python/).
