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.
- 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")
- 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)
- 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
- 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
- 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
- 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