Extrair Texto e Tabelas de PDF em Python com pypdf e pdfplumber

Aprenda a extrair texto e tabelas de PDF em Python com pypdf e pdfplumber: leitura página por página, metadados, mesclar e dividir arquivos, exportar tabelas de notas fiscais e boletos para Excel e CSV, e OCR de PDFs escaneados com Tesseract. Guia prático em português brasileiro.

7 min de leitura Equipe Python Brasil

O PDF é o formato dominante na papelada brasileira: notas fiscais eletrônicas impressas em DANFE, boletos bancários, holerites, contratos, relatórios contábeis e editais. Quase todo escritório, contador ou analista já perdeu tempo copiando dados de um PDF, linha por linha, para uma planilha. A boa notícia é que o Python lê PDFs muito bem: com pypdf e pdfplumber você extrai texto, tabelas e metadados de forma programática e transforma horas de trabalho manual em um script de alguns minutos.

Este tutorial mostra como extrair texto e tabelas de PDFs em Python, do caso mais simples (texto selecionável) ao mais desafiador (PDF escaneado que exige OCR), com exemplos voltados para a realidade brasileira. Se você já automatiza planilhas, gera relatórios em PDF ou edita documentos do Word, este é o complemento natural: agora você também consegue ler de volta o que o escritório recebeu. Quem está começando pode revisar o guia de Python para iniciantes e a introdução à automação com Python.

pypdf ou pdfplumber? (e onde entra o PyMuPDF)

Antes de instalar, vale entender qual ferramenta usar em cada situação:

  • pypdf — biblioteca pura em Python, sem dependências nativas. Excelente para extrair texto simples, ler metadados (autor, título, data) e estruturar PDFs (mesclar, dividir, girar páginas). É o substituto moderno do antigo PyPDF2, renomeado em 2022.
  • pdfplumber — construído sobre o pdfminer.six. É a melhor escolha para extrair tabelas e para preservar o posicionamento do texto na página. É mais lento que o pypdf em arquivos grandes, mas devolve dados muito mais estruturados.
  • PyMuPDF (importado como fitz) — o mais rápido dos três, ideal para processar milhares de PDFs. Depende de uma biblioteca em C, o que pode dificultar a instalação em alguns servidores.

A regra prática: comece com pypdf para texto e estruturação, e traga o pdfplumber quando aparecer uma tabela. Vamos cobrir os dois.

Instale os dois pacotes no seu ambiente virtual:

pip install pypdf pdfplumber

Extraindo texto com pypdf

O pypdf organiza um PDF em um objeto PdfReader, que expõe a lista de páginas. Cada página tem o método extract_text():

from pypdf import PdfReader

reader = PdfReader("nota-fiscal.pdf")
print(f"Total de páginas: {len(reader.pages)}")

# Texto de todas as páginas concatenado
texto_completo = ""
for pagina in reader.pages:
    texto_completo += pagina.extract_text() + "\n"

print(texto_completo[:500])

Para ler apenas uma página, use o índice: reader.pages[0].extract_text(). Em notas fiscais, a primeira página costuma trazer o cabeçalho com emitente, destinatário e totais; as seguintes podem trazer o detalhamento dos itens.

Metadados do documento

Os metadados ficam em reader.metadata e ajudam a identificar origem e data de emissão — útil para organizar arquivos recebidos por e-mail em lotes:

meta = reader.metadata
print(meta.get("/Title"))      # título definido pelo emissor
print(meta.get("/Author"))     # autor
print(meta.get("/CreationDate"))  # ex.: D:20260717143000-03'00'

O campo /CreationDate segue um padrão próprio do PDF (D:YYYYMMDDHHmmss±TZ). Se for relevante, recorte os oito primeiros dígitos após D: para obter a data.

Mesclar e dividir PDFs

O pypdf também resolve tarefas estruturais que antes exigiam ferramentas pagas. Para juntar vários PDFs (por exemplo, agrupar os DANFEs de um mês):

from pypdf import PdfWriter

escritor = PdfWriter()
for arquivo in ["nf-001.pdf", "nf-002.pdf", "nf-003.pdf"]:
    escritor.append(arquivo)

with open("notas-janeiro.pdf", "wb") as saida:
    escritor.write(saida)

Para dividir — extrair apenas as páginas de 1 a 3 de um contrato, por exemplo:

from pypdf import PdfReader, PdfWriter

reader = PdfReader("contrato.pdf")
escritor = PdfWriter()
for i in range(0, 3):                # páginas 1, 2 e 3 (índices começam em 0)
    escritor.add_page(reader.pages[i])

with open("contrato-resumo.pdf", "wb") as saida:
    escritor.write(saida)

Extraindo tabelas com pdfplumber

Quando o dado que você precisa está em uma tabela — itens de uma nota fiscal, parcelas de um boleto, demonstrativo de resultados — o pdfplumber é a ferramenta certa. Ele entende linhas e colunas e devolve listas de listas prontas para virar planilha:

import pdfplumber

with pdfplumber.open("demonstrativo.pdf") as pdf:
    pagina = pdf.pages[0]
    texto = pagina.extract_text()
    tabelas = pagina.extract_tables()

for i, tabela in enumerate(tabelas, start=1):
    print(f"--- Tabela {i} ({len(tabela)} linhas) ---")
    for linha in tabela:
        print(linha)

Cada linha é uma lista de células, em que células vazias aparecem como None. O método extract_table() devolve apenas a primeira tabela da página; extract_tables() devolve todas.

Ajustando a estratégia de extração

Nem toda tabela tem bordas visíveis. O pdfplumber permite ajustar como ele detecta colunas e linhas:

tabela = pagina.extract_table({
    "vertical_strategy": "lines",     # "lines", "text" ou "explicit"
    "horizontal_strategy": "lines",
})

Use "lines" quando o documento tem grade completa (notas fiscais com bordas), e "text" quando as colunas são definidas apenas pelo espaçamento entre as palavras (comum em boletos e relatórios financeiros). É normal experimentar: rode uma vez, inspecione o resultado e ajuste.

Limpando as linhas extraídas

PDFs reais trazem linhas em branco, cabeçalhos repetidos e células com quebras de linha. Uma função de limpeza deixa a tabela pronta para exportar:

def limpar_tabela(tabela):
    limpa = []
    for linha in tabela:
        if not linha or all(celula is None for celula in linha):
            continue                      # descarta linhas vazias
        linha = [(celula or "").strip().replace("\n", " ") for celula in linha]
        limpa.append(linha)
    return limpa

tabela = limpar_tabela(tabela)

Depois disso, vale validar com expressões regulares os campos críticos: conferir se o CNPJ tem 14 dígitos, se o valor bate com o total da nota e se a data está no formato DD/MM/AAAA.

Exportando para Excel e CSV

A tabela extraída ganha vida quando vira planilha. Para CSV, use o módulo da biblioteca padrão descrito no guia de leitura e escrita de CSV:

import csv

with open("itens-nota.csv", "w", encoding="utf-8", newline="") as f:
    escritor = csv.writer(f, delimiter=";")
    escritor.writerows(tabela)

Para Excel, use o openpyxl:

from openpyxl import Workbook

wb = Workbook()
ws = wb.active
for linha in tabela:
    ws.append(linha)
wb.save("itens-nota.xlsx")

Cuidado com a vírgula decimal brasileira: valores extraídos costumam vir como "1.234,56". Converta para float antes de gravar como número, trocando os separadores:

def para_numero(texto):
    if not texto:
        return None
    texto = texto.replace(".", "").replace(",", ".")
    try:
        return float(texto)
    except ValueError:
        return None

Assim, "1.234,56" vira 1234.56 e é gravado corretamente na planilha.

Quando o PDF é uma imagem: OCR com Tesseract

Se o extract_text() devolver uma string vazia ou praticamente nada, o PDF provavelmente é uma imagem escaneada — não há texto selecionável. Nesse caso, é preciso converter as páginas em imagem e aplicar OCR. A combinação clássica é pdf2image (que exige o poppler instalado no sistema) com pytesseract (que exige o Tesseract):

pip install pdf2image pytesseract
from pdf2image import convert_from_path
import pytesseract

imagens = convert_from_path("boleto-escaneado.pdf", dpi=300)
for i, imagem in enumerate(imagens, start=1):
    texto = pytesseract.image_to_string(imagem, lang="por")  # "por" = português
    print(f"--- Página {i} ---")
    print(texto)

O parâmetro lang="por" ativa o pacote de idioma português do Tesseract, essencial para reconhecer acentos corretamente. Como o OCR nunca é perfeito, sempre revise campos sensíveis como valores, datas e CNPJ. Para chamar o Tesseract diretamente da linha de comando, combinar com outras ferramentas nativas ou orquestrar conversões, vale conhecer o guia do módulo subprocess.

Boas práticas e armadilhas

  • Feche os arquivos. Sempre use with pdfplumber.open(...) as pdf para liberar os recursos ao final.
  • Cuidado com a memória em lotes grandes. Processar milhares de PDFs de uma vez exige liberar cada PdfReader/objeto de página entre iterações; considere processar em lotes e gravar resultados incrementalmente.
  • Não confie cegamente no OCR. Para documentos fiscais, cruze o total extraído com o campo de total da nota. Para dados sensíveis de pessoas, siga a LGPD: armazene apenas o necessário e controle o acesso.
  • Diferencie texto de imagem logo no início. Se extract_text() devolver vazio, pule direto para o fluxo de OCR em vez de insistir.
  • Padronize nomes de saída. Salve os resultados com identificadores extraídos do próprio PDF (número da nota, CNPJ do emitente) para evitar arquivos duplicados.

Conclusão

Extrair texto e tabelas de PDFs é uma das automações de maior impacto para quem trabalha com a papelada brasileira. Com pypdf você lê texto, metadados e estrutura arquivos; com pdfplumber você transforma tabelas de notas fiscais, boletos e demonstrativos em dados limpos; e quando o documento é uma imagem, o fluxo de OCR com Tesseract recupera o texto escaneado. Combinado com a exportação para Excel e CSV, e com a capacidade de gerar PDFs quando preciso, o Python fecha o ciclo completo de manipulação de documentos. Comece com um PDF pequeno e selecionável, valide o resultado e expanda gradualmente para os cenários mais complexos — sempre com revisão humana nos campos críticos.

E

Equipe Python Brasil

Contribuidor do Python Brasil — Aprenda Python em Português