python-docx: Como Criar e Editar Word com Python
Aprenda python-docx para criar e editar arquivos Word com Python: textos, tabelas, imagens, templates, contratos em lote e conversão para PDF na prática.
A forma mais direta de criar e editar arquivos Word com Python é usar a biblioteca python-docx. Ela gera documentos .docx sem exigir que o Microsoft Word esteja instalado e permite automatizar textos, estilos, tabelas, imagens, cabeçalhos e contratos baseados em templates. Para instalar, rode pip install python-docx; no código, importe Document do pacote docx.
Esse fluxo economiza tempo em rotinas de escritório: em vez de copiar um modelo, trocar nome, data e valor manualmente, um script pode produzir dezenas de contratos, propostas comerciais, certificados ou relatórios personalizados. O arquivo final abre normalmente no Microsoft Word, LibreOffice e Google Docs.
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.
O que é possível fazer com python-docx?
| Tarefa | Suporte | Abordagem recomendada |
|---|---|---|
| Criar textos, títulos e listas | Sim | add_paragraph() e add_heading() |
| Montar tabelas e inserir imagens | Sim | add_table() e add_picture() |
Abrir e alterar um .docx existente | Sim | Document("arquivo.docx") |
| Preencher contratos a partir de modelo | Sim | template com marcadores ou docxtpl |
| Converter Word para PDF | Não diretamente | LibreOffice headless ou docx2pdf |
Editar arquivos .doc antigos | Não | converter primeiro para .docx |
| Reproduzir todos os recursos do Word | Parcial | template pronto ou manipulação de XML |
A biblioteca é ideal quando o resultado precisa continuar editável. Se você só precisa entregar um arquivo final para impressão, pode ser melhor gerar o PDF diretamente com Python. Para extrair texto de vários formatos, incluindo .docx, .xlsx e .pptx, veja também o guia do MarkItDown em Python.
Instalação e primeiros passos
A python-docx é uma biblioteca de terceiros. Instale dentro do seu ambiente virtual com pip ou com uv:
# Com pip
python -m pip install python-docx
# Ou, em um projeto gerenciado com uv
uv add python-docx
O nome instalado é python-docx, mas o nome usado no import é docx. Instalar um pacote chamado apenas docx por engano pode causar conflito; se isso aconteceu, remova-o com python -m pip uninstall docx e instale 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.
Perguntas frequentes sobre python-docx
python-docx é gratuito para uso comercial?
Sim. O projeto usa licença MIT e pode ser adotado em aplicações comerciais. A biblioteca trabalha diretamente com o formato .docx, sem depender de uma licença ou instalação local do Microsoft Word.
Preciso ter o Microsoft Word instalado?
Não para criar, ler ou editar o documento. O Word pode ser necessário apenas em fluxos específicos de conversão para PDF com docx2pdf. Em servidores Linux, uma alternativa comum é chamar o LibreOffice em modo headless com o módulo subprocess.
Qual é a diferença entre python-docx e docxtpl?
python-docx oferece uma API para construir e modificar o documento elemento por elemento. docxtpl é mais conveniente quando uma pessoa prepara o visual no Word e o Python apenas preenche variáveis, repete linhas de tabelas ou aplica condições com sintaxe inspirada em Jinja2. Para contratos e propostas complexas, normalmente vale combinar as duas bibliotecas.
Como converter o .docx gerado para PDF?
A conversão não faz parte do python-docx. No Windows e no macOS, docx2pdf usa o Word instalado. Em Linux, o LibreOffice headless costuma ser a opção mais prática. Se o documento não precisa permanecer editável, gerar o relatório em PDF desde o início reduz dependências.
Por que a substituição de uma variável não funciona no template?
O Word pode dividir um marcador como {{nome}} em vários runs internos, especialmente quando há mudanças de estilo ou revisão ortográfica. Digite o marcador de uma vez e mantenha a mesma formatação em todo o trecho. Se o template tiver muitas variáveis ou tabelas dinâmicas, prefira docxtpl.
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.