File size: 9,690 Bytes
08c80af
8db827b
 
08c80af
 
8db827b
 
08c80af
 
12e2c64
8db827b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12e2c64
8db827b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
08c80af
8db827b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
08c80af
 
 
 
 
 
 
8db827b
08c80af
8db827b
 
08c80af
8db827b
08c80af
8db827b
 
 
 
 
08c80af
 
 
 
12e2c64
08c80af
 
 
 
 
 
 
 
 
 
 
 
 
8db827b
 
 
 
 
 
 
 
 
 
 
08c80af
 
8db827b
08c80af
8db827b
08c80af
 
 
 
 
8db827b
 
 
 
 
 
 
 
 
08c80af
 
8db827b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
import requests
from bs4 import BeautifulSoup
import json
import re
import pandas as pd
from io import BytesIO
from collections import namedtuple
import numpy as np
import streamlit as st

def clean_text(text):
    return re.sub(r'\s+', ' ', text).strip()

def formatta_numero(stringa):
    stringa = stringa.split(',')[0]
    stringa = stringa.replace(".", "").replace("da", "").replace("€", "").replace("%","").replace("m²", "").replace("locali", "").strip()
    stringa = stringa.split(' ')[0]
    return stringa

# Estrae le informazioni dagli ANNUNCI
def extract_info(provincia, comune, prezzo_medio_mq, listing):
    info = {}
    superficie = ""
    locali = ""
    info['Provincia'] = provincia
    info['Comune'] = comune
    price_elem = listing.find('div', class_='in-listingCardPrice')
    prezzo = clean_text(price_elem.text) if price_elem else ""
    link_elem = listing.find('a', class_='in-listingCardTitle')
    if link_elem:
        link = link_elem['href']
        titolo = link_elem.text.strip()
    feature_list = listing.find('div', class_='in-listingCardFeatureList')
    if feature_list:
        for item in feature_list.find_all('div', class_='in-listingCardFeatureList__item'):
            use_elem = item.find('use', class_='nd-icon__use')
            if use_elem:
                if use_elem.get('xlink:href') == '#planimetry':
                    locali = item.find('span').text.strip()                  
                elif use_elem.get('xlink:href') == '#size':
                    superficie = item.find('span').text.strip()  
    image_url = ""
    img = listing.find('figure', class_='nd-figure nd-ratio in-photo')
    if img:
        image_url = img.find('img')['src']   
    
    superficie = formatta_numero(superficie)
    locali = formatta_numero(locali)
    prezzo = formatta_numero(prezzo)
    info['Immagine'] = image_url
    info['Titolo'] = titolo
    info['Prezzo'] =  int(prezzo)
    info['Superficie'] = int(superficie)
    try:
        prezzo_numerico = int(prezzo)
        superficie_numerica = int(superficie)
        info['PrezzoMq'] = prezzo_numerico // superficie_numerica 
        prezzo_medio_mq = formatta_numero(prezzo_medio_mq)
        prezzo_medio_mq_numerico = int(prezzo_medio_mq)
        differenza = prezzo_medio_mq_numerico - info['PrezzoMq']
        vantaggio = (differenza / prezzo_medio_mq_numerico) * 100
        vantaggio = max(0, vantaggio)
        vantaggio = int(vantaggio)
    except (ValueError, ZeroDivisionError):
        info['PrezzoMq'] = 0
        vantaggio = 0
    info['Locali'] = int(locali)
    info['Link'] = link
    info['PrezzoMedioMq'] = int(prezzo_medio_mq)
    info['Vantaggio'] = vantaggio
    if info['PrezzoMq']< int(prezzo_medio_mq) and info['PrezzoMq']>0:
        info['Vantaggioso'] = True
    else:
        info['Vantaggioso'] = False
    return info

# Legge gli ANNUNCI (pagina x pagina) sulla base del COMUNE di appartenenza
def scrape_immobiliare(provincia, comune, prezzo_medio_mq, prezzo_minimo, prezzo_massimo, locali_minimo, locali_massimo):
    print(provincia + " " + comune + " " + prezzo_medio_mq)
    comune_url = comune.replace(" ", "-")
    base_url = f"https://www.immobiliare.it/vendita-case/{comune_url}/?prezzoMinimo={prezzo_minimo}&prezzoMassimo={prezzo_massimo}&localiMinimo={locali_minimo}&localiMassimo={locali_massimo}&random=123456"
    results = []
    page = 1
    url = base_url
    while True:
        print(f'Elaborazione pagina {page}')
        response = requests.get(url)
        soup = BeautifulSoup(response.content, 'html.parser')
        listings = soup.find_all('li', class_='nd-list__item in-searchLayoutListItem')
        if not listings:
            break
        for listing in listings:
            results.append(extract_info(provincia, comune, prezzo_medio_mq, listing))
        pagination = soup.find('div', class_='in-pagination__list')
        if pagination:
            next_page = pagination.find('a', class_='in-pagination__item', string=lambda text: text and text.strip().isdigit())
            if not next_page:
                break
        page += 1
        url = base_url + '&pag=' + str(page)

    return json.dumps(results, ensure_ascii=False, indent=2)

# Restituisce l'elenco dei COMUNI di una Provincia e il PREZZO MEDIO
def get_elenco_comuni(provincia):
    base_url = f"https://www.immobiliare.it/mercato-immobiliare/lombardia/{provincia}-provincia/"
    results = []
    print(f'Lettura Comuni e Prezzo Medio al Mq')
    response = requests.get(base_url)
    soup = BeautifulSoup(response.content, 'html.parser')
    rows = soup.find_all('tr', class_='nd-table__row')
    results = []
    for row in rows:
        cells = row.find_all('td', class_='nd-table__cell')
        if len(cells) >= 2:
            comune = cells[0].get_text(strip=True)
            prezzo_vendita = cells[1].get_text(strip=True)
            results.append({
                'provincia': provincia,
                'comune': comune,
                'prezzo': prezzo_vendita
            })

    return results 

st.set_page_config(layout="wide")

st.title('🏠 Immobiliare A.I. ')
st.write("##### Il tuo assistente di intelligenza artificiale per la ricerca di occasioni immobiliari")
with st.expander("Informazioni"):
    st.write("Immobiliare A.I. è la webapp che semplifica la ricerca di immobili, grazie a algoritmi avanzati che calcolano il vantaggio di ogni offerta. Trova le migliori occasioni sul mercato con analisi precise e personalizzate. Scopri l’immobile giusto per te con facilità e sicurezza!")
    
cerca_premuto = False
comuni_provincia = {}

with st.sidebar: 
    comuni_provincia = get_elenco_comuni('Brescia')
    st.title("Filtri")
    elenco = [d['comune'] for d in comuni_provincia]
    comune_input = st.multiselect(
        "Comuni",
        elenco
    )
    prezzo_minimo = st.sidebar.slider("Prezzo Minimo", min_value=0, max_value=1000, value=200)
    prezzo_massimo = st.sidebar.slider("Prezzo Massimo", min_value=0, max_value=1000, value=230)

    locali = list(range(1, 21))  # Intervallo da 1 a 10
    
    # Select slider unico per selezionare l'intervallo del numero di locali
    locali_range = st.sidebar.select_slider(
        "Locali",
        options=locali,
        value=(locali[2], locali[4])  # Valore iniziale, da 1 a 5 locali
    )

    # Dividi il range in minimo e massimo numero di locali
    locali_minimo, locali_massimo = locali_range
    prezzo_minimo = prezzo_minimo*1000
    prezzo_massimo = prezzo_massimo*1000
    cerca_premuto = st.button("Cerca", use_container_width=True, type='primary')

#
#if __name__ == "__main__":
#    print(df)
    
def scrivi_dataframe(output):
    if len(output) > 0: 
        df = pd.DataFrame(output)
        df = df.sort_values(by=["Vantaggio", "PrezzoMq"], ascending=[False, True])
        columns_to_display = ["Vantaggioso", "Vantaggio", "Immagine", "Comune", "Titolo", "PrezzoMq", "Prezzo", "Superficie", "Locali", "PrezzoMedioMq", "Link"]
        df = df[columns_to_display]
        df = df.style.format(thousands='.')
        st.dataframe(df, hide_index=True, use_container_width=True, 
                    column_config ={
                        "Vantaggioso": st.column_config.CheckboxColumn("Vantaggioso"), 
                        "Vantaggio": st.column_config.ProgressColumn(
                            "Punteggio",
                            help="Vantaggio in %",
                            format='%f',
                            min_value=0,
                            max_value=100,
                        ),
                        "Immagine": st.column_config.ImageColumn("Anteprima", help="Anteprima", width="small"),
                        "PrezzoMq": "€/Mq",
                        "PrezzoMedioMq": "Media €/Mq",
                        "Prezzo": st.column_config.NumberColumn(
                                    "Prezzo Totale",
                                    help="Il prezzo totale dell'immobile in EURO",
                                    step=1,
                                    format="%d €",
                                ),
                        "Superficie": "Superficie",
                        "Locali": "Locali",
                        "Link": st.column_config.LinkColumn("App URL")
                    })    
    


if cerca_premuto:
    comuni_selezionati = comune_input
    comuni_selezionati = [comune.upper() for comune in comuni_selezionati]
    output = []
    output_singolo = []
    for comune_provincia in comuni_provincia:
        if comune_provincia['comune'].upper() in comuni_selezionati:
            with st.spinner(f"Ricerca Immobili Comune: {comune_provincia['comune']}"):
                output_singolo = json.loads(scrape_immobiliare(comune_provincia['provincia'], 
                                                                comune_provincia['comune'], 
                                                                comune_provincia['prezzo'], 
                                                                prezzo_minimo, 
                                                                prezzo_massimo, 
                                                                locali_minimo, 
                                                                locali_massimo))
                st.write(f"### {comune_provincia['comune']}")
                scrivi_dataframe(output_singolo)
                st.divider()
                output += output_singolo
    if len(comuni_selezionati)>1:
        st.write(f"### Comuni Selezionati")
        scrivi_dataframe(output)
    st.success("Elaborazione Completata")
else:
    st.error("Per favore, inserisci il nome di un comune.")