jcalbornoz commited on
Commit
49850dc
·
verified ·
1 Parent(s): 36317c1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +26 -15
app.py CHANGED
@@ -32,6 +32,12 @@ except ImportError:
32
  subprocess.run(["pip", "install", "fake-useragent"], check=True)
33
  from fake_useragent import UserAgent
34
 
 
 
 
 
 
 
35
  # --- DESCARGA SEGURA DE FOTOS ---
36
  def descargar_imagen(url, idx):
37
  if not url or len(url) < 5 or url.startswith("data:"):
@@ -94,9 +100,9 @@ def extraer_ubicacion(texto):
94
  for linea in lineas[1:4]:
95
  if "$" not in linea and not linea.isdigit() and "m²" not in linea:
96
  return linea[:60]
97
- return "Ubicación en zona solicitada"
98
 
99
- # --- 3. MOTOR DE EXTRACCIÓN ROBUSTO (ENLACES + RADAR DE FOTOS) ---
100
  def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo, hab, ban, park, antiguedad, ascensor, piscina):
101
  resultados = []
102
  log_visible = ""
@@ -116,15 +122,13 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
116
  log_visible += "🔄 FR: Buscando inmuebles y fotos...\n"
117
  page.goto(url_fr, wait_until="domcontentloaded", timeout=60000)
118
 
119
- # Espera ACTIVA para que Finca Raíz cargue el código de Javascript
120
  try: page.wait_for_load_state("networkidle", timeout=10000)
121
  except: pass
122
 
123
  for _ in range(4):
124
  page.mouse.wheel(0, 1000)
125
- page.wait_for_timeout(2000) # Pausa interna de Playwright
126
 
127
- # VOLVIMOS A BUSCAR TODOS LOS ENLACES (ESTO NO FALLA)
128
  elementos = page.query_selector_all("a")
129
  cont_fr = 0
130
  for el in elementos:
@@ -137,11 +141,9 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
137
  href = el.get_attribute("href")
138
  if not href: continue
139
 
140
- # RADAR DE FOTO: Busca dentro del enlace, o sube al contenedor padre
141
  img_url = ""
142
  img_el = el.query_selector("img")
143
  if not img_el:
144
- # Busca en el elemento superior (abuelo)
145
  padre = el.evaluate_handle("el => el.parentElement ? el.parentElement.parentElement : null")
146
  if padre: img_el = padre.query_selector("img")
147
 
@@ -163,7 +165,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
163
  cont_fr += 1
164
  except: continue
165
  page.close()
166
- log_visible += f"✅ FR: Encontrados {cont_fr} candidatos brutos.\n"
167
  except Exception as e: log_visible += f"⚠️ Error buscando en FR.\n"
168
 
169
  # --- METROCUADRADO ---
@@ -209,7 +211,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
209
  cont_mc += 1
210
  except: continue
211
  page.close()
212
- log_visible += f"✅ MC: Encontrados {cont_mc} candidatos brutos.\n"
213
  except Exception as e: log_visible += f"⚠️ Error buscando en MC.\n"
214
 
215
  browser.close()
@@ -228,7 +230,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
228
 
229
  log_visible += f"\n✨ PROCESANDO PDF CON {len(df_final)} INMUEBLES..."
230
 
231
- # --- PDF VISUAL ---
232
  pdf_path = f"Reporte_Visual_{int(time.time())}.pdf"
233
  pdf = FPDF()
234
  pdf.add_page()
@@ -236,7 +238,9 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
236
  pdf.set_font("Arial", 'B', 16)
237
  pdf.set_fill_color(40, 53, 147)
238
  pdf.set_text_color(255, 255, 255)
239
- pdf.cell(0, 15, f" REPORTE INMOBILIARIO: {barrio.upper()} ({operacion.upper()})", ln=True, fill=True)
 
 
240
  pdf.set_text_color(0, 0, 0)
241
  pdf.ln(5)
242
 
@@ -260,17 +264,24 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
260
  pdf.set_x(text_x)
261
  pdf.set_font("Arial", 'B', 9)
262
  pdf.set_text_color(100, 100, 100)
263
- pdf.cell(0, 5, f"📍 {r['Ubicacion']} | Fuente: {r['Portal']}", ln=True)
 
 
 
 
 
 
 
264
 
265
  pdf.set_x(text_x)
266
  pdf.set_font("Arial", '', 8)
267
  pdf.set_text_color(0, 0, 0)
268
- pdf.multi_cell(0, 4, f"{r['Descripcion']}")
269
 
270
  pdf.set_x(text_x)
271
  pdf.set_font("Arial", 'U', 8)
272
  pdf.set_text_color(0, 102, 204)
273
- pdf.cell(0, 5, "🔗 Hacer clic aquí para ver publicación", link=r['URL'], ln=True)
274
  pdf.set_text_color(0, 0, 0)
275
 
276
  y_end = pdf.get_y()
@@ -305,7 +316,7 @@ def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo,
305
 
306
  # --- INTERFAZ GRÁFICA ---
307
  with gr.Blocks() as demo:
308
- gr.Markdown("## 📸 TramitIA Pro: Generador Visual (Escáner Indestructible)")
309
 
310
  with gr.Row():
311
  with gr.Column(scale=1):
 
32
  subprocess.run(["pip", "install", "fake-useragent"], check=True)
33
  from fake_useragent import UserAgent
34
 
35
+ # --- FILTRO ANTI-EMOJIS PARA EL PDF ---
36
+ def sanear_texto(texto):
37
+ """Elimina emojis y caracteres especiales que rompen el PDF (latin-1)"""
38
+ if not isinstance(texto, str): return ""
39
+ return texto.encode('latin-1', 'ignore').decode('latin-1')
40
+
41
  # --- DESCARGA SEGURA DE FOTOS ---
42
  def descargar_imagen(url, idx):
43
  if not url or len(url) < 5 or url.startswith("data:"):
 
100
  for linea in lineas[1:4]:
101
  if "$" not in linea and not linea.isdigit() and "m²" not in linea:
102
  return linea[:60]
103
+ return "Ubicacion en zona solicitada"
104
 
105
+ # --- 3. MOTOR DE EXTRACCIÓN ROBUSTO ---
106
  def motor_tramitia_visual(operacion, barrio, ciudad, area, m2_min, m2_max, tipo, hab, ban, park, antiguedad, ascensor, piscina):
107
  resultados = []
108
  log_visible = ""
 
122
  log_visible += "🔄 FR: Buscando inmuebles y fotos...\n"
123
  page.goto(url_fr, wait_until="domcontentloaded", timeout=60000)
124
 
 
125
  try: page.wait_for_load_state("networkidle", timeout=10000)
126
  except: pass
127
 
128
  for _ in range(4):
129
  page.mouse.wheel(0, 1000)
130
+ page.wait_for_timeout(2000)
131
 
 
132
  elementos = page.query_selector_all("a")
133
  cont_fr = 0
134
  for el in elementos:
 
141
  href = el.get_attribute("href")
142
  if not href: continue
143
 
 
144
  img_url = ""
145
  img_el = el.query_selector("img")
146
  if not img_el:
 
147
  padre = el.evaluate_handle("el => el.parentElement ? el.parentElement.parentElement : null")
148
  if padre: img_el = padre.query_selector("img")
149
 
 
165
  cont_fr += 1
166
  except: continue
167
  page.close()
168
+ log_visible += f"✅ FR: Encontrados {cont_fr} candidatos.\n"
169
  except Exception as e: log_visible += f"⚠️ Error buscando en FR.\n"
170
 
171
  # --- METROCUADRADO ---
 
211
  cont_mc += 1
212
  except: continue
213
  page.close()
214
+ log_visible += f"✅ MC: Encontrados {cont_mc} candidatos.\n"
215
  except Exception as e: log_visible += f"⚠️ Error buscando en MC.\n"
216
 
217
  browser.close()
 
230
 
231
  log_visible += f"\n✨ PROCESANDO PDF CON {len(df_final)} INMUEBLES..."
232
 
233
+ # --- PDF VISUAL (AHORA SANEADO) ---
234
  pdf_path = f"Reporte_Visual_{int(time.time())}.pdf"
235
  pdf = FPDF()
236
  pdf.add_page()
 
238
  pdf.set_font("Arial", 'B', 16)
239
  pdf.set_fill_color(40, 53, 147)
240
  pdf.set_text_color(255, 255, 255)
241
+ # Saneamos el encabezado por si acaso
242
+ encabezado = sanear_texto(f" REPORTE INMOBILIARIO: {barrio.upper()} ({operacion.upper()})")
243
+ pdf.cell(0, 15, encabezado, ln=True, fill=True)
244
  pdf.set_text_color(0, 0, 0)
245
  pdf.ln(5)
246
 
 
264
  pdf.set_x(text_x)
265
  pdf.set_font("Arial", 'B', 9)
266
  pdf.set_text_color(100, 100, 100)
267
+
268
+ # Saneamiento de textos dinámicos
269
+ ubicacion_limpia = sanear_texto(r['Ubicacion'])
270
+ portal_limpio = sanear_texto(r['Portal'])
271
+ desc_limpia = sanear_texto(r['Descripcion'])
272
+
273
+ # Textos limpios sin emojis hardcodeados
274
+ pdf.cell(0, 5, f"Ubicacion: {ubicacion_limpia} | Fuente: {portal_limpio}", ln=True)
275
 
276
  pdf.set_x(text_x)
277
  pdf.set_font("Arial", '', 8)
278
  pdf.set_text_color(0, 0, 0)
279
+ pdf.multi_cell(0, 4, desc_limpia)
280
 
281
  pdf.set_x(text_x)
282
  pdf.set_font("Arial", 'U', 8)
283
  pdf.set_text_color(0, 102, 204)
284
+ pdf.cell(0, 5, ">> Hacer clic aqui para ver publicacion", link=r['URL'], ln=True)
285
  pdf.set_text_color(0, 0, 0)
286
 
287
  y_end = pdf.get_y()
 
316
 
317
  # --- INTERFAZ GRÁFICA ---
318
  with gr.Blocks() as demo:
319
+ gr.Markdown("## 📸 TramitIA Pro: Generador Visual Saneado")
320
 
321
  with gr.Row():
322
  with gr.Column(scale=1):