jcalbornoz commited on
Commit
84a07b9
·
verified ·
1 Parent(s): ead6977

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +107 -108
app.py CHANGED
@@ -11,8 +11,8 @@ import time
11
  # --- CONFIGURACIÓN DE ENTORNO ---
12
  try:
13
  subprocess.run(["playwright", "install", "chromium"], check=True)
14
- except Exception as e:
15
- print(f"Playwright listo.")
16
 
17
  from playwright.sync_api import sync_playwright
18
 
@@ -21,128 +21,127 @@ USER_AGENTS = [
21
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
22
  ]
23
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  def extraer_datos(page, area_m2):
25
  referencias = []
26
- # Esperar selectores de tarjetas de inmuebles
27
- page.wait_for_selector("article, [class*='Card'], [class*='listing']", timeout=20000)
28
- cards = page.query_selector_all("article, [class*='Card'], .listing-item")[:5]
29
-
30
- for card in cards:
31
- try:
32
- # Extraer URL
33
- link_elem = card.query_selector("a")
34
- url = "https://www.fincaraiz.com.co" + link_elem.get_attribute("href") if link_elem else "N/A"
35
-
36
- # Extraer Texto y Descripción
37
- full_text = card.inner_text()
38
- lineas = [l.strip() for l in full_text.split('\n') if len(l.strip()) > 5]
39
- descripcion = lineas[0] if lineas else "Sin descripción"
40
-
41
- # Limpiar números para precio
42
- solo_nums = full_text.replace('.', '').replace('$', '')
43
- nums = [int(s) for s in solo_nums.split() if s.isdigit() and len(s) >= 6]
44
-
45
- if nums:
46
- precio = max(nums)
47
- # Intentar buscar área en el texto, si no usar la del usuario
48
- area_ref = next((int(n) for n in solo_nums.split() if n.isdigit() and 20 < int(n) < 500), area_m2)
49
-
50
- referencias.append({
51
- "Portal": "Finca Raíz",
52
- "Descripción": descripcion[:100] + "...",
53
- "Precio": precio,
54
- "Area": area_ref,
55
- "Precio_M2": precio / area_ref,
56
- "URL": url
57
- })
58
- except: continue
59
  return referencias
60
 
61
- def analizar_mercado(zona, area_m2, tipo_inmueble, modo):
62
  with sync_playwright() as p:
63
  browser = p.chromium.launch(headless=True)
64
  context = browser.new_context(user_agent=random.choice(USER_AGENTS))
65
  page = context.new_page()
66
-
67
  zona_url = zona.lower().replace(" ", "-")
68
- # Diccionario de URLs según modo
69
- path_modo = "arriendo" if modo == "Arriendo" else "venta"
70
- url = f"https://www.fincaraiz.com.co/{tipo_inmueble.lower()}/{path_modo}/{zona_url}"
71
 
72
- try:
73
- page.goto(url, wait_until="domcontentloaded", timeout=60000)
74
- time.sleep(random.uniform(1, 2))
75
- datos = extraer_datos(page, area_m2)
76
- browser.close()
77
- return datos
78
- except Exception as e:
79
- if 'browser' in locals(): browser.close()
80
- return []
81
-
82
- def comparativa_tramitia(zona, area_m2, tipo):
83
- # Ejecutar ambas búsquedas
84
- res_arriendo = analizar_mercado(zona, area_m2, tipo, "Arriendo")
85
- res_venta = analizar_mercado(zona, area_m2, tipo, "Venta")
86
-
87
- if not res_arriendo and not res_venta:
88
- return "❌ No se encontraron datos suficientes para comparar.", None, None
89
 
90
- df_a = pd.DataFrame(res_arriendo)
91
- df_v = pd.DataFrame(res_venta)
92
-
93
- html_resumen = f"<div style='padding:20px; border-radius:10px; background-color:#f8fafc; border:1px solid #e2e8f0;'>"
94
- html_resumen += f"<h2 style='color:#1e40af;'>📊 Comparativa TramitIA Pro: {zona}</h2>"
95
-
96
- if not df_a.empty:
97
- prom_a = df_a['Precio'].mean()
98
- html_resumen += f"<p style='font-size:1.1em;'>🏠 <b>Promedio Arriendo:</b> ${prom_a:,.0f} COP</p>"
99
-
100
- if not df_v.empty:
101
- prom_v = df_v['Precio'].mean()
102
- html_resumen += f"<p style='font-size:1.1em;'>💰 <b>Promedio Venta:</b> ${prom_v:,.0f} COP</p>"
103
- if not df_a.empty:
104
- rentabilidad = ( (df_a['Precio'].mean() * 12) / prom_v ) * 100
105
- html_resumen += f"<div style='margin-top:10px; padding:10px; background:#dcfce7; color:#166534; border-radius:5px;'>"
106
- html_resumen += f"<b>Rentabilidad Estimada (PER):</b> {rentabilidad:,.2f}% anual</div>"
107
-
108
- html_resumen += "</div>"
109
-
110
- # Unir ambos dataframes para mostrar las referencias detalladas
111
- df_a['Tipo'] = 'Arriendo'
112
- df_v['Tipo'] = 'Venta'
113
  df_final = pd.concat([df_a, df_v], ignore_index=True)
 
 
 
 
 
 
 
 
 
 
 
 
114
 
115
- # Generar PDF
116
- pdf_path = "Comparativa_TramitIA.pdf"
117
- # (Lógica simplificada de PDF para el ejemplo)
118
 
119
- return html_resumen, df_final, pdf_path
120
 
121
- # --- INTERFAZ GRADIO ---
122
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
123
- gr.HTML("<h1 style='text-align:center; color:#1e40af;'>🤖 TramitIA Pro</h1>")
124
- gr.HTML("<p style='text-align:center;'>Análisis Comparativo de Mercado (Arriendo vs Venta)</p>")
125
-
126
  with gr.Row():
127
  with gr.Column(scale=1):
128
- zona_in = gr.Textbox(label="Zona/Barrio y Ciudad", placeholder="Ej: El Salitre Bogota")
129
- area_in = gr.Number(label="Área M2", value=80)
130
- tipo_in = gr.Dropdown(["Apartamento", "Casa", "Oficina"], label="Tipo", value="Apartamento")
131
- btn_comp = gr.Button("COMPARAR ARRIENDO VS VENTA", variant="primary")
132
-
133
  with gr.Column(scale=2):
134
- res_html = gr.HTML()
135
- with gr.Tabs():
136
- with gr.TabItem("Detalle de Referencias"):
137
- data_view = gr.Dataframe(interactive=False)
138
- with gr.TabItem("Descargas"):
139
- file_out = gr.File(label="Reporte Técnico PDF")
140
-
141
- btn_comp.click(
142
- comparativa_tramitia,
143
- inputs=[zona_in, area_in, tipo_in],
144
- outputs=[res_html, data_view, file_out]
145
- )
146
-
147
- if __name__ == "__main__":
148
- demo.launch()
 
11
  # --- CONFIGURACIÓN DE ENTORNO ---
12
  try:
13
  subprocess.run(["playwright", "install", "chromium"], check=True)
14
+ except Exception:
15
+ pass
16
 
17
  from playwright.sync_api import sync_playwright
18
 
 
21
  "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
22
  ]
23
 
24
+ # --- GENERADOR DE PDF (CORREGIDO) ---
25
+ def generar_pdf_comparativo(zona, area, df):
26
+ pdf = FPDF()
27
+ pdf.add_page()
28
+ pdf.set_font("Arial", 'B', 16)
29
+ pdf.cell(0, 15, "TRAMITIA PRO - REPORTE COMPARATIVO", ln=True, align='C')
30
+ pdf.set_font("Arial", '', 10)
31
+ pdf.cell(0, 5, f"Fecha: {datetime.datetime.now().strftime('%d/%m/%Y')}", ln=True, align='C')
32
+ pdf.ln(10)
33
+
34
+ pdf.set_font("Arial", 'B', 12)
35
+ pdf.cell(0, 10, f"Analisis para: {zona.upper()} - Area: {area}m2", ln=True)
36
+ pdf.ln(5)
37
+
38
+ # Tabla de referencias
39
+ pdf.set_font("Arial", 'B', 9)
40
+ pdf.set_fill_color(200, 220, 255)
41
+ pdf.cell(20, 10, "Tipo", 1, 0, 'C', True)
42
+ pdf.cell(80, 10, "Descripcion", 1, 0, 'C', True)
43
+ pdf.cell(45, 10, "Precio", 1, 0, 'C', True)
44
+ pdf.cell(45, 10, "Valor m2", 1, 1, 'C', True)
45
+
46
+ pdf.set_font("Arial", '', 8)
47
+ for _, r in df.iterrows():
48
+ tipo = str(r['Tipo'])
49
+ desc = str(r['Descripción'])[:45]
50
+ precio = f"${r['Precio']:,.0f}"
51
+ val_m2 = f"${r['Precio_M2']:,.0f}"
52
+
53
+ pdf.cell(20, 10, tipo, 1)
54
+ pdf.cell(80, 10, desc, 1)
55
+ pdf.cell(45, 10, precio, 1)
56
+ pdf.cell(45, 10, val_m2, 1, 1)
57
+
58
+ path_pdf = "Comparativa_TramitIA.pdf"
59
+ pdf.output(path_pdf)
60
+ return path_pdf
61
+
62
+ # --- LÓGICA DE EXTRACCIÓN ---
63
  def extraer_datos(page, area_m2):
64
  referencias = []
65
+ try:
66
+ page.wait_for_selector("article, [class*='Card'], [class*='listing']", timeout=15000)
67
+ cards = page.query_selector_all("article, [class*='Card'], .listing-item")[:5]
68
+ for card in cards:
69
+ try:
70
+ link_elem = card.query_selector("a")
71
+ url = "https://www.fincaraiz.com.co" + link_elem.get_attribute("href") if link_elem else "N/A"
72
+ full_text = card.inner_text()
73
+ solo_nums = full_text.replace('.', '').replace('$', '')
74
+ nums = [int(s) for s in solo_nums.split() if s.isdigit() and len(s) >= 6]
75
+ if nums:
76
+ precio = max(nums)
77
+ area_ref = next((int(n) for n in solo_nums.split() if n.isdigit() and 20 < int(n) < 500), area_m2)
78
+ referencias.append({
79
+ "Portal": "Finca Raíz",
80
+ "Descripción": full_text.split('\n')[0][:50],
81
+ "Precio": precio,
82
+ "Area": area_ref,
83
+ "Precio_M2": precio / area_ref,
84
+ "URL": url
85
+ })
86
+ except: continue
87
+ except: pass
 
 
 
 
 
 
 
 
 
 
88
  return referencias
89
 
90
+ def comparar_mercado_tramitia(zona, area_m2, tipo):
91
  with sync_playwright() as p:
92
  browser = p.chromium.launch(headless=True)
93
  context = browser.new_context(user_agent=random.choice(USER_AGENTS))
94
  page = context.new_page()
 
95
  zona_url = zona.lower().replace(" ", "-")
 
 
 
96
 
97
+ # Búsqueda Arriendo
98
+ page.goto(f"https://www.fincaraiz.com.co/{tipo.lower()}/arriendo/{zona_url}", wait_until="domcontentloaded")
99
+ data_a = extraer_datos(page, area_m2)
100
+
101
+ # Búsqueda Venta
102
+ page.goto(f"https://www.fincaraiz.com.co/{tipo.lower()}/venta/{zona_url}", wait_until="domcontentloaded")
103
+ data_v = extraer_datos(page, area_m2)
104
+
105
+ browser.close()
 
 
 
 
 
 
 
 
106
 
107
+ if not data_a and not data_v:
108
+ return "⚠️ No se hallaron datos.", None, None
109
+
110
+ df_a = pd.DataFrame(data_a); df_a['Tipo'] = 'Arriendo'
111
+ df_v = pd.DataFrame(data_v); df_v['Tipo'] = 'Venta'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
112
  df_final = pd.concat([df_a, df_v], ignore_index=True)
113
+
114
+ # CÁLCULOS
115
+ prom_a = df_a['Precio'].mean() if not df_a.empty else 0
116
+ prom_v = df_v['Precio'].mean() if not df_v.empty else 0
117
+
118
+ resumen_html = f"""
119
+ <div style='padding:15px; background:#f0f9ff; border-radius:10px; border:1px solid #bae6fd;'>
120
+ <h3 style='color:#0369a1; margin:0;'>📊 Comparativa TramitIA Pro</h3>
121
+ <p>Promedio Arriendo: <b>${prom_a:,.0f} COP</b></p>
122
+ <p>Promedio Venta: <b>${prom_v:,.0f} COP</b></p>
123
+ </div>
124
+ """
125
 
126
+ # GENERACIÓN OBLIGATORIA DEL PDF
127
+ pdf_generado = generar_pdf_comparativo(zona, area_m2, df_final)
 
128
 
129
+ return resumen_html, df_final, pdf_generado
130
 
131
+ # --- INTERFAZ ---
132
  with gr.Blocks(theme=gr.themes.Soft()) as demo:
133
+ gr.HTML("<h1 style='text-align:center'>🤖 TramitIA Pro</h1>")
 
 
134
  with gr.Row():
135
  with gr.Column(scale=1):
136
+ zona = gr.Textbox(label="Zona (Ciudad y Barrio)")
137
+ area = gr.Number(label="M2", value=70)
138
+ tipo = gr.Dropdown(["Apartamento", "Casa"], label="Tipo", value="Apartamento")
139
+ btn = gr.Button("EJECUTAR COMPARATIVA", variant="primary")
 
140
  with gr.Column(scale=2):
141
+ res = gr.HTML()
142
+ table = gr.Dataframe(label="Referencias Detalladas")
143
+ file = gr.File(label="Descargar Reporte PDF")
144
+
145
+ btn.click(comparar_mercado_tramitia, [zona, area, tipo], [res, table, file])
146
+
147
+ demo.launch()