jcalbornoz commited on
Commit
af4b44e
·
verified ·
1 Parent(s): ffcd56b

Create recolector.py

Browse files
Files changed (1) hide show
  1. recolector.py +135 -0
recolector.py ADDED
@@ -0,0 +1,135 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sqlite3
2
+ import time
3
+ import random
4
+ import re
5
+ from duckduckgo_search import DDGS
6
+ import pandas as pd
7
+ from datetime import datetime
8
+
9
+ # --- CONFIGURACIÓN DEL ROBOT ---
10
+ DB_NAME = "base_datos_inmobiliaria.db"
11
+ CIUDADES_ZONAS = {
12
+ "Bogota": ["Salitre", "Chico", "Chapinero", "Cedritos", "Colina Campestre", "Suba", "Kennedy", "Modelia"],
13
+ "Medellin": ["Poblado", "Laureles", "Envigado", "Belen", "Sabaneta"],
14
+ "Cali": ["Ciudad Jardin", "El Peñon", "Valle del Lili", "Granada"],
15
+ "Cartagena": ["Bocagrande", "Castillogrande", "Manga", "Crespo"]
16
+ }
17
+
18
+ # --- 1. GESTIÓN DE BASE DE DATOS ---
19
+ def iniciar_db():
20
+ conn = sqlite3.connect(DB_NAME)
21
+ c = conn.cursor()
22
+ # Creamos una tabla robusta para guardar histórico
23
+ c.execute('''CREATE TABLE IF NOT EXISTS mercado (
24
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
25
+ ciudad TEXT,
26
+ zona TEXT,
27
+ titulo TEXT,
28
+ precio REAL,
29
+ area REAL,
30
+ precio_m2 REAL,
31
+ url TEXT UNIQUE,
32
+ fuente TEXT,
33
+ fecha_captura DATE
34
+ )''')
35
+ conn.commit()
36
+ conn.close()
37
+
38
+ def guardar_dato(dato):
39
+ conn = sqlite3.connect(DB_NAME)
40
+ c = conn.cursor()
41
+ try:
42
+ # INSERT OR IGNORE evita duplicados si ya escaneamos esa URL
43
+ c.execute('''INSERT OR IGNORE INTO mercado
44
+ (ciudad, zona, titulo, precio, area, precio_m2, url, fuente, fecha_captura)
45
+ VALUES (?,?,?,?,?,?,?,?,?)''',
46
+ (dato['ciudad'], dato['zona'], dato['titulo'], dato['precio'],
47
+ dato['area'], dato['precio_m2'], dato['url'], dato['fuente'], datetime.now().date()))
48
+ conn.commit()
49
+ return c.rowcount # Retorna 1 si guardó, 0 si ya existía
50
+ except Exception as e:
51
+ print(f"Error guardando: {e}")
52
+ return 0
53
+ finally:
54
+ conn.close()
55
+
56
+ # --- 2. MOTOR DE EXTRACCIÓN (PARSEERS) ---
57
+ def limpiar_precio(texto):
58
+ match = re.search(r'\$\s?([\d.,]+)', texto)
59
+ if match:
60
+ clean = match.group(1).replace('.', '').replace(',', '')
61
+ try: return float(clean)
62
+ except: return 0
63
+ return 0
64
+
65
+ def limpiar_area(texto):
66
+ match = re.search(r'(\d+)\s?(m2|mt)', texto.lower())
67
+ if match:
68
+ try: return float(match.group(1))
69
+ except: return 0
70
+ return 0
71
+
72
+ # --- 3. EL ROBOT (CRAWLER) ---
73
+ def robot_inmobiliario():
74
+ print("🤖 INICIANDO ROBOT RECOLECTOR DE DATA INMOBILIARIA...")
75
+ iniciar_db()
76
+
77
+ total_nuevos = 0
78
+
79
+ # Recorremos cada ciudad y zona configurada
80
+ for ciudad, zonas in CIUDADES_ZONAS.items():
81
+ for zona in zonas:
82
+ print(f"\n📡 Escaneando: {ciudad} - {zona}...")
83
+
84
+ # Usamos DuckDuckGo para buscar fichas específicas sin entrar al portal (Anti-Bloqueo)
85
+ # Buscamos en los 3 grandes portales
86
+ query = f'site:fincaraiz.com.co/inmueble OR site:metrocuadrado.com/inmueble OR site:casas.mitula.com.co venta apartamento "{ciudad}" "{zona}"'
87
+
88
+ try:
89
+ # Usamos el backend 'api' o 'html'
90
+ results = DDGS().text(query, max_results=20)
91
+
92
+ if not results:
93
+ print(" ⚠️ No se encontraron resultados nuevos.")
94
+
95
+ count_zona = 0
96
+ for r in results:
97
+ texto = f"{r['title']} {r['body']}"
98
+ precio = limpiar_precio(texto)
99
+ area = limpiar_area(texto)
100
+
101
+ # Filtros de Calidad de Dato
102
+ if precio > 50000000 and area > 10:
103
+ dato = {
104
+ 'ciudad': ciudad,
105
+ 'zona': zona,
106
+ 'titulo': r['title'],
107
+ 'precio': precio,
108
+ 'area': area,
109
+ 'precio_m2': round(precio/area, 2),
110
+ 'url': r['href'],
111
+ 'fuente': 'Web Scraping'
112
+ }
113
+
114
+ guardado = guardar_dato(dato)
115
+ if guardado:
116
+ count_zona += 1
117
+ total_nuevos += 1
118
+ print(f" ✅ Guardado: {titulo[:30]}... (${precio:,.0f})")
119
+
120
+ print(f" 📊 Resumen {zona}: {count_zona} inmuebles nuevos agregados.")
121
+
122
+ # PAUSA ESTRATÉGICA (Dormir para parecer humano)
123
+ tiempo_espera = random.uniform(2, 5)
124
+ print(f" 💤 Durmiendo {tiempo_espera:.1f} segundos...")
125
+ time.sleep(tiempo_espera)
126
+
127
+ except Exception as e:
128
+ print(f" ❌ Error en zona {zona}: {e}")
129
+ time.sleep(5) # Espera de error
130
+
131
+ print(f"\n🏁 CICLO TERMINADO. Total inmuebles nuevos en base de datos: {total_nuevos}")
132
+
133
+ if __name__ == "__main__":
134
+ # Ejecutar el robot
135
+ robot_inmobiliario()