Automação de PDFs com Python: Extração, Edição e Geração de Documentos

Automação de PDFs com Python

O formato PDF (Portable Document Format) é amplamente utilizado por manter a aparência independentemente do sistema ou dispositivo. Em projetos de automação, é comum extrair informações, unificar documentos, proteger arquivos e converter outros formatos para PDF. A seguir, você verá como realizar essas tarefas com Python usando bibliotecas especializadas.

  1. Manipulação de PDFs com PyMuPDF

Um arquivo PDF é composto por cabeçalho, corpo, tabela de referência cruzada e trailer. Conhecer essa organização facilita o entendimento das operações de leitura e escrita.

Instalação

pip install pymupdf

Extraindo texto

import fitz
from pathlib import Path

def extrair_texto(caminho_pdf):
    arquivo = Path(caminho_pdf)
    if not arquivo.exists():
        raise FileNotFoundError(f"Arquivo não encontrado: {arquivo}")

    partes = []
    with fitz.open(arquivo) as documento:
        for numero, pagina in enumerate(documento, start=1):
            conteudo = pagina.get_text()
            partes.append(f"\n--- Página {numero} ---\n{conteudo}")
    return "".join(partes)

# Uso
pdf_exemplo = "exemplo.pdf"
try:
    texto = extrair_texto(pdf_exemplo)
    print(texto[:500])
    Path("texto_extraido.txt").write_text(texto, encoding="utf-8")
    print("Texto salvo com sucesso.")
except Exception as erro:
    print(f"Erro ao extrair texto: {erro}")

Extraindo imagens

import fitz
from pathlib import Path

def extrair_imagens(caminho_pdf, pasta_saida="imagens_extraidas"):
    destino = Path(pasta_saida)
    destino.mkdir(parents=True, exist_ok=True)

    documento = fitz.open(caminho_pdf)
    quantidade = 0

    for num_pagina, pagina in enumerate(documento, start=1):
        for indice, img in enumerate(pagina.get_images(full=True), start=1):
            xref = img[0]
            extracao = documento.extract_image(xref)
            extensao = extracao["ext"]
            nome = destino / f"pag_{num_pagina}_img_{indice}.{extensao}"
            nome.write_bytes(extracao["image"])
            quantidade += 1

    documento.close()
    return quantidade

# Uso
try:
    total = extrair_imagens("exemplo.pdf")
    print(f"{total} imagens extraídas.")
except Exception as erro:
    print(f"Erro ao extrair imagens: {erro}")

Adicionando marca d'água

import fitz

def adicionar_marca(entrada, saida, texto):
    documento = fitz.open(entrada)

    for pagina in documento:
        retangulo = pagina.rect
        central_x = retangulo.width / 2
        central_y = retangulo.height / 2

        escritor = fitz.TextWriter(retangulo)
        escritor.append(
            (central_x, central_y),
            texto,
            fontsize=40,
            color=(0.6, 0.6, 0.6),
        )
        escritor.write_text(pagina, opacity=0.25)

    documento.save(saida)
    documento.close()

# Uso
adicionar_marca("exemplo.pdf", "com_marca.pdf", "CONFIDENCIAL")

  1. Extração de tabelas com pdfplumber

Quando o documento contém tabelas, o pdfplumber identifica células mesmo quando as bordas são invisíveis, inferindo a partir da posição do texto.

Instalação

pip install pdfplumber pandas openpyxl

Convertendo tabelas para DataFrame

import pdfplumber
import pandas as pd

def tabelas_para_dataframe(caminho_pdf):
    tabelas = []
    with pdfplumber.open(caminho_pdf) as pdf:
        for numero, pagina in enumerate(pdf.pages, start=1):
            for tabela in pagina.extract_tables() or []:
                if not tabela:
                    continue
                df = pd.DataFrame(tabela[1:], columns=tabela[0])
                df["pagina"] = numero
                tabelas.append(df)
    return pd.concat(tabelas, ignore_index=True) if tabelas else None

# Uso
resultado = tabelas_para_dataframe("documento_com_tabelas.pdf")
if resultado is not None:
    resultado.to_excel("tabelas_extraidas.xlsx", index=False)

  1. Operações com PyPDF2

O PyPDF2 é uma biblioteca versátil para unir, dividir, criptografar e descriptografar PDFs.

Instalação

pip install PyPDF2

Unindo PDFs

from PyPDF2 import PdfMerger

def unificar_pdfs(arquivos, arquivo_saida):
    if not arquivos:
        raise ValueError("A lista de arquivos está vazia.")

    mesclador = PdfMerger()
    try:
        for arquivo in arquivos:
            mesclador.append(arquivo)
            print(f"Adicionado: {arquivo}")
        mesclador.write(arquivo_saida)
    finally:
        mesclador.close()
    return arquivo_saida

# Uso
unificar_pdfs(["relatorio.pdf", "anexos.pdf"], "documento_final.pdf")

Dividindo PDF por página

from PyPDF2 import PdfReader, PdfWriter
import os

def separar_paginas(entrada, pasta_saida="paginas"):
    os.makedirs(pasta_saida, exist_ok=True)
    leitor = PdfReader(entrada)
    base = os.path.splitext(os.path.basename(entrada))[0]

    for indice, pagina in enumerate(leitor.pages, start=1):
        escritor = PdfWriter()
        escritor.add_page(pagina)
        caminho = os.path.join(pasta_saida, f"{base}_pag_{indice}.pdf")
        with open(caminho, "wb") as f:
            escritor.write(f)
    return len(leitor.pages)

# Uso
separar_paginas("exemplo.pdf")

Criptografia e descriptografia

from PyPDF2 import PdfReader, PdfWriter

def criptografar_pdf(entrada, saida, senha):
    leitor = PdfReader(entrada)
    escritor = PdfWriter()
    for pagina in leitor.pages:
        escritor.add_page(pagina)
    escritor.encrypt(senha)
    with open(saida, "wb") as f:
        escritor.write(f)
    return saida

def descriptografar_pdf(entrada, saida, senha):
    leitor = PdfReader(entrada)
    if not leitor.is_encrypted:
        raise ValueError("O PDF não está protegido por senha.")

    if leitor.decrypt(senha) != 1:
        raise ValueError("Senha incorreta.")

    escritor = PdfWriter()
    for pagina in leitor.pages:
        escritor.add_page(pagina)
    with open(saida, "wb") as f:
        escritor.write(f)
    return saida

  1. Convertendo HTML e páginas web para PDF

Para transformar conteúdo web em PDF, é comum utilizar o wkhtmltopdf junto com a biblioteca pdfkit.

Instalação

Primeiro, instale o utilitário wkhtmltopdf no sistema operacional. Em seguida, instale a biblioteca Python:

pip install pdfkit

Conversão de URL, arquivo e string HTML

import pdfkit

def url_para_pdf(url, saida):
    pdfkit.from_url(url, saida)
    return saida

def arquivo_html_para_pdf(caminho_html, saida):
    pdfkit.from_file(caminho_html, saida)
    return saida

def string_html_para_pdf(conteudo_html, saida):
    pdfkit.from_string(conteudo_html, saida)
    return saida

Capturando página como imagem

import subprocess

def capturar_pagina(url, imagem_saida):
    subprocess.run(
        ["wkhtmltoimage", "--quality", "85", url, imagem_saida],
        check=True,
    )
    return imagem_saida

  1. Gerando PDF a partir de documentos Office

Word para PDF

from docx2pdf import convert
from pathlib import Path

def word_para_pdf(caminho_docx, caminho_pdf=None):
    docx = Path(caminho_docx)
    if caminho_pdf is None:
        caminho_pdf = docx.with_suffix(".pdf")
    convert(str(docx), str(caminho_pdf))
    return caminho_pdf

Excel para PDF no Windows

import os
import win32com.client

def excel_para_pdf(caminho_xlsx, caminho_pdf=None):
    caminho = os.path.abspath(caminho_xlsx)
    if caminho_pdf is None:
        caminho_pdf = os.path.splitext(caminho)[0] + ".pdf"
    caminho_pdf = os.path.abspath(caminho_pdf)

    app = win32com.client.Dispatch("Excel.Application")
    app.Visible = False
    try:
        planilha = app.Workbooks.Open(caminho)
        planilha.ExportAsFixedFormat(0, caminho_pdf)
        planilha.Close()
    finally:
        app.Quit()
    return caminho_pdf

  1. Cenários práticos

Processamanto em lote de faturas

import re
import fitz
import pandas as pd
from pathlib import Path

def processar_faturas(pasta, planilha_saida):
    pasta = Path(pasta)
    registros = []

    for arquivo in pasta.glob("*.pdf"):
        with fitz.open(arquivo) as doc:
            texto = doc[0].get_text()

        numero = re.search(r"N[º°]\s*(\d+)", texto)
        data = re.search(r"Data[:\s]+(\d{2}/\d{2}/\d{4})", texto)
        valor = re.search(r"Valor\s+R?\$?\s*([\d.,]+)", texto)

        registros.append({
            "arquivo": arquivo.name,
            "numero": numero.group(1) if numero else None,
            "data": data.group(1) if data else None,
            "valor": float(valor.group(1).replace(".", "").replace(",", ".")) if valor else 0.0,
        })

    df = pd.DataFrame(registros)
    df.to_excel(planilha_saida, index=False)
    return df

Geração automatizada de relatório

import pandas as pd
import matplotlib.pyplot as plt
import pdfkit
from pathlib import Path

def relatorio_vendas(caminho_csv, pdf_saida):
    df = pd.read_csv(caminho_csv)
    resumo = df.groupby("produto")["receita"].sum()

    grafico = "vendas.png"
    resumo.plot(kind="bar", figsize=(8, 5), color="steelblue")
    plt.title("Receita por Produto")
    plt.tight_layout()
    plt.savefig(grafico)

    html = f"""
    <html>
      <body>
        <h1>Relatório de Vendas</h1>
        <p><strong>Total recebido:</strong> R$ {df['receita'].sum():,.2f}</p>
        <img src='{grafico}' />
      </body>
    </html>
    """

    pdfkit.from_string(html, pdf_saida)
    return pdf_saida

Tags: Python PyMuPDF pdfplumber PyPDF2 pdfkit

Publicado em 7-9 18:36