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.

06 Jul 2026 10 min de leitura Equipe Python Dev BR

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?

TarefaSuporteAbordagem recomendada
Criar textos, títulos e listasSimadd_paragraph() e add_heading()
Montar tabelas e inserir imagensSimadd_table() e add_picture()
Abrir e alterar um .docx existenteSimDocument("arquivo.docx")
Preencher contratos a partir de modeloSimtemplate com marcadores ou docxtpl
Converter Word para PDFNão diretamenteLibreOffice headless ou docx2pdf
Editar arquivos .doc antigosNãoconverter primeiro para .docx
Reproduzir todos os recursos do WordParcialtemplate 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, 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:

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 .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 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:

  1. Combine documentos e planilhas — leia uma planilha Excel 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 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.

E
Equipe Python Dev BR

Contribuidor do Python Dev BR

Artigos relacionados