ESJL commited on
Commit
27a23e6
·
verified ·
1 Parent(s): 0f6880e

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +180 -0
app.py ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pypdf import PdfReader
2
+ import re
3
+ from datetime import datetime
4
+ from openpyxl import Workbook
5
+ from openpyxl.styles import Font, PatternFill, Alignment
6
+ import requests
7
+ from io import BytesIO
8
+ import gradio as gr
9
+ import tempfile
10
+ import os
11
+
12
+ # URL da página do CUB-RS
13
+ CUB_PAGE_URL = "https://sinduscon-rs.com.br/cub-rs/"
14
+
15
+ LINHAS = [
16
+ "R 1-B (Res. Unifamiliar)",
17
+ "R 1-N (Res. Unifamiliar)",
18
+ "R 1-A (Res. Unifamiliar)",
19
+ "PP 4-B (Prédio Popular)",
20
+ "PP 4-N (Prédio Popular)",
21
+ "R 8-B (Res. Multifamiliar)",
22
+ "R 8-N (Res. Multifamiliar)",
23
+ "R 8-A (Res. Multifamiliar)",
24
+ "R 16-N (Res. Multifamiliar)",
25
+ "R 16-A (Res. Multifamiliar)",
26
+ "PIS (Projeto Inter. Social)",
27
+ "RP1Q (Residência Popular)",
28
+ "CAL 8-N (Com. Andar Livres)",
29
+ "CAL 8-A (Com. Andar Livres)",
30
+ "CSL 8-N (Com.Salas e Lojas)",
31
+ "CSL 8-A (Com.Salas e Lojas)",
32
+ "CSL 16-N (Com.Salas e Lojas)",
33
+ "CSL 16-A (Com.Salas e Lojas)",
34
+ "GI (Galpão Industrial)"
35
+ ]
36
+
37
+ NUM_LINHAS = len(LINHAS)
38
+ DATA_MINIMA = datetime(2007, 2, 1)
39
+
40
+ MESES_PT = {
41
+ 1: "Janeiro", 2: "Fevereiro", 3: "Março", 4: "Abril",
42
+ 5: "Maio", 6: "Junho", 7: "Julho", 8: "Agosto",
43
+ 9: "Setembro", 10: "Outubro", 11: "Novembro", 12: "Dezembro"
44
+ }
45
+
46
+ GRUPOS_LINHAS = [
47
+ (2, 4), (5, 6), (7, 9), (10, 11), (12, 12),
48
+ (13, 13), (14, 15), (16, 17), (18, 19), (20, 20),
49
+ ]
50
+
51
+ CINZA = PatternFill(start_color="D9D9D9", end_color="D9D9D9", fill_type="solid")
52
+
53
+
54
+ def fetch_pdf_url():
55
+ response = requests.get(CUB_PAGE_URL, timeout=30)
56
+ response.raise_for_status()
57
+ pattern = r'href="([^"]+)"[^>]*>\s*Série Histórica [–-] Valor\s*</a>'
58
+ match = re.search(pattern, response.text, re.IGNORECASE)
59
+ if not match:
60
+ raise ValueError("Link do PDF não encontrado.")
61
+ return match.group(1)
62
+
63
+
64
+ def download_pdf(url):
65
+ response = requests.get(url, timeout=60)
66
+ response.raise_for_status()
67
+ return BytesIO(response.content)
68
+
69
+
70
+ def br_to_float(v):
71
+ return float(v.replace(".", "").replace(",", "."))
72
+
73
+
74
+ def extract_numbers(text):
75
+ nums = re.findall(r"\d{1,3}(?:\.\d{3})*,\d{2}", text)
76
+ return [br_to_float(n) for n in nums]
77
+
78
+
79
+ def extract_year_from_page(text):
80
+ match = re.search(r"EVOLUÇÃO\s*%?/?\s*(20\d{2})", text)
81
+ if match:
82
+ return int(match.group(1))
83
+ years = re.findall(r"(20\d{2})", text)
84
+ return max(map(int, years)) if years else None
85
+
86
+
87
+ def detect_start_month(num_meses, ano, ano_mais_recente):
88
+ if num_meses == 12 or ano == ano_mais_recente:
89
+ return 1
90
+ return 12 - num_meses + 1
91
+
92
+
93
+ def format_month_header(col_name):
94
+ ano, mes = col_name.split("-")
95
+ return f"{MESES_PT[int(mes)]}/{ano}"
96
+
97
+
98
+ def apply_formatting(ws, num_colunas):
99
+ ws.column_dimensions['A'].width = 30
100
+ for col_idx in range(2, num_colunas + 1):
101
+ ws.column_dimensions[ws.cell(1, col_idx).column_letter].width = 15
102
+
103
+ for col_idx in range(1, num_colunas + 1):
104
+ cell = ws.cell(row=1, column=col_idx)
105
+ cell.font = Font(bold=True)
106
+ cell.alignment = Alignment(horizontal='center')
107
+
108
+ for grupo_idx, (ini, fim) in enumerate(GRUPOS_LINHAS):
109
+ if grupo_idx % 2 == 0:
110
+ for r in range(ini, fim + 1):
111
+ for c in range(1, num_colunas + 1):
112
+ ws.cell(r, c).fill = CINZA
113
+
114
+
115
+ def gerar_excel():
116
+ log = []
117
+ pdf_url = fetch_pdf_url()
118
+ log.append(f"PDF encontrado: {pdf_url}")
119
+
120
+ pdf_data = download_pdf(pdf_url)
121
+ reader = PdfReader(pdf_data)
122
+
123
+ ano_mais_recente = extract_year_from_page(reader.pages[0].extract_text())
124
+ dados = {}
125
+
126
+ for page in reader.pages:
127
+ text = page.extract_text()
128
+ ano = extract_year_from_page(text)
129
+ if not ano:
130
+ continue
131
+
132
+ valores = extract_numbers(text)
133
+ num_meses = len(valores) // NUM_LINHAS
134
+ mes_inicial = detect_start_month(num_meses, ano, ano_mais_recente)
135
+
136
+ for linha_idx in range(NUM_LINHAS):
137
+ for mes_idx in range(num_meses):
138
+ pos = linha_idx * num_meses + mes_idx
139
+ if pos >= len(valores):
140
+ break
141
+ data = datetime(ano, mes_inicial + mes_idx, 1)
142
+ if data < DATA_MINIMA:
143
+ continue
144
+ dados[(linha_idx, data.strftime("%Y-%m"))] = valores[pos]
145
+
146
+ colunas = sorted(set(c for _, c in dados.keys()))
147
+
148
+ wb = Workbook()
149
+ ws = wb.active
150
+ ws.title = "CUB Histórico"
151
+
152
+ ws.append(["CÓDIGO"] + [format_month_header(c) for c in colunas])
153
+
154
+ for i, codigo in enumerate(LINHAS):
155
+ row = [codigo] + [dados.get((i, c)) for c in colunas]
156
+ ws.append(row)
157
+
158
+ apply_formatting(ws, len(colunas) + 1)
159
+
160
+ temp_file = tempfile.NamedTemporaryFile(delete=False, suffix=".xlsx")
161
+ wb.save(temp_file.name)
162
+
163
+ log.append("Excel gerado com sucesso.")
164
+ return temp_file.name, "\n".join(log)
165
+
166
+
167
+ # Interface Gradio
168
+ interface = gr.Interface(
169
+ fn=gerar_excel,
170
+ inputs=[],
171
+ outputs=[
172
+ gr.File(label="📥 Baixar Excel"),
173
+ gr.Textbox(label="Log de execução")
174
+ ],
175
+ title="CUB/RS – Série Histórica",
176
+ description="Baixa automaticamente o PDF do SINDUSCON-RS e gera o Excel da série histórica."
177
+ )
178
+
179
+ if __name__ == "__main__":
180
+ interface.launch()