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 ou gera relatórios em PDF, 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 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:
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:
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:
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:
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:
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:
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:
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:
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:
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, oreplacepode não encontrar o trecho inteiro. Adocxtpllida com isso automaticamente.
Lendo e editando documentos existentes
Abrir um .docx para extrair ou modificar conteúdo é igualmente simples:
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 .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
.docxe use o script só para preencher. - Versione seus modelos. Guarde
template_v1.docx,template_v2.docxno 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 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.
Próximos passos
Para evoluir depois deste tutorial:
- Combine documentos e planilhas — leia uma planilha Excel com a lista de clientes e gere um contrato
.docxpara cada linha. - Exporte para PDF — encadeie a geração do
.docxcom uma conversão para PDF quando o documento for assinado. - Automatize o envio — conecte a geração do documento ao envio de e-mails com Python 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 e o guia de primeiro emprego como programador Python.
Equipe Python Brasil
Contribuidor do Python Brasil — Aprenda Python em Português