-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathextractTablePDF.py
More file actions
143 lines (116 loc) · 4.91 KB
/
Copy pathextractTablePDF.py
File metadata and controls
143 lines (116 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import pdfplumber
import pandas as pd
import os
import re
import tkinter as tk
from tkinter import filedialog
root = tk.Tk()
root.withdraw() # Esconde a janela principal do tkinter
pdf_path = filedialog.askopenfilename(
title="Selecione o arquivo PDF",
filetypes=[("Arquivos PDF", "*.pdf"), ("Todos os arquivos", "*.*")]
)
if not pdf_path:
print("Nenhum arquivo selecionado. Encerrando.")
exit()
# --- SELEÇÃO DO LOCAL PARA SALVAR O EXCEL ---
excel_output_path = filedialog.asksaveasfilename(
title="Salvar planilha Excel como",
defaultextension=".xlsx",
filetypes=[("Planilha Excel", "*.xlsx")]
)
if not excel_output_path:
print("Nenhum local de salvamento selecionado. Encerrando.")
exit()
vertical_lines = [17.1, 39.7, 62, 264, 311.9, 382.68, 411.41, 438.65, 510.24, 578.27]
table_settings = {
"explicit_vertical_lines": vertical_lines,
"horizontal_strategy": "text",
"snap_x_tolerance": 5,
"snap_y_tolerance": 5,
"min_words_vertical": 2,
}
all_rows = []
# --- 1. EXTRAÇÃO BRUTA DE TODAS AS PÁGINAS ---
with pdfplumber.open(pdf_path) as pdf:
for page_ind, p0 in enumerate(pdf.pages):
top = 100.14 if page_ind == 0 else 17.57
bottom = 824.34
bbox = (0, top, p0.width, bottom)
cropped = p0.crop(bbox)
t = cropped.extract_table(table_settings)
if not t:
continue
# Não assumimos mais que t[0] é o cabeçalho. Pegamos tudo.
all_rows.extend(t)
# --- 2. PÓS-PROCESSAMENTO DETALHISTA COM REGEX ---
processed_rows = []
header_index = -1
for idx, row in enumerate(all_rows):
str_row = [str(cell).strip() if cell is not None else "" for cell in row]
str_row = [re.sub(r'\n', ' ', cell) for cell in str_row]
joined_text = " ".join(filter(None, str_row))
joined_text_no_spaces = joined_text.replace(" ", "").lower()
# Identifica onde está o verdadeiro cabeçalho da tabela
if "filial" in joined_text_no_spaces and "produto" in joined_text_no_spaces:
header_index = len(processed_rows) # Salva a posição do cabeçalho
processed_rows.append(str_row)
continue
# Regra A: Linha do Colaborador (Ex: "1034 - JOHN I ROCHA")
colab_match = re.match(r"^(\d+)\s*-\s*(.+)$", joined_text)
if colab_match:
id_num = colab_match.group(1).strip()
nome = colab_match.group(2).strip()
# Coloca o ID na primeira célula e o nome na segunda. O resto fica vazio.
new_row = [f"{id_num} -", nome] + [""] * (len(row) - 2)
processed_rows.append(new_row)
continue
# Regra B: Linha "Total Produtos" (Mesmo fragmentado como "Total P roduto s")
if "totalprodutos" in joined_text_no_spaces:
new_row = ["Total Produtos:"]
# Percorre as células em busca dos valores numéricos que restaram
for cell_val in str_row[1:]:
if re.search(r"\d", cell_val):
new_row.append(cell_val)
else:
new_row.append("")
# Ajusta o tamanho da linha para coincidir com as outras
while len(new_row) < len(row): new_row.append("")
processed_rows.append(new_row[:len(row)])
continue
# Regra C: Linha "Totais"
if joined_text_no_spaces.startswith("totais"):
new_row = ["Totais:"]
for cell_val in str_row[1:]:
if re.search(r"\d", cell_val):
new_row.append(cell_val)
else:
new_row.append("")
while len(new_row) < len(row): new_row.append("")
processed_rows.append(new_row[:len(row)])
continue
# Adiciona linhas normais que não entraram em nenhuma regra
processed_rows.append(str_row)
# --- 3. MONTAGEM DO DATAFRAME ---
if processed_rows and header_index != -1:
# O DataFrame é criado usando a linha identificada como verdadeiro cabeçalho
df = pd.DataFrame(processed_rows)
df.columns = df.iloc[header_index]
# Remove as linhas repetidas de cabeçalho (caso o PDF tenha múltiplas páginas)
df = df[df[df.columns[0]] != df.columns[0]]
# Limpeza rigorosa
df = df.replace(r'^\s*$', pd.NA, regex=True)
df = df.dropna(how='all', axis=1)
df = df.fillna("")
nome_aba = "COLABORADOR"
# Se o arquivo Excel já existir, abre em modo de adição ('a')
if os.path.exists(excel_output_path):
with pd.ExcelWriter(excel_output_path, engine="openpyxl", mode="a", if_sheet_exists="replace") as writer:
df.to_excel(writer, sheet_name=nome_aba, index=False)
print(f"Pronto! A aba '{nome_aba}' foi salva/atualizada no arquivo existente '{excel_output_path}'.")
else:
# Se o arquivo não existir, cria um arquivo novo
df.to_excel(excel_output_path, index=False, sheet_name=nome_aba)
print(f"Pronto! O novo arquivo '{excel_output_path}' foi criado com a aba '{nome_aba}'.")
else:
print("Nenhuma tabela válida encontrada ou cabeçalho ausente.")