Moment Of Truth | 03:33 Minuti
Il tuo touchpoint sullo spazio digitale: uno strumento pratico dove troverai idee, riflessioni, conoscenze e framework in grado di guidarti nell’esecuzione della tua innovazione digitale. Testala, è gratis ↓
Buondì, e buon lunedì.
Quanti articoli ha il tuo blog o quello del tuo cliente?
Sono sicuro al 90% che tu non sappia rispondere. Ogni blog cresce per accumulo: più contenuti, più copertura. Più articoli, più opportunità di risposta: scriviamo per informare, per convertire, per posizionarci. E poi, a un certo punto, perdiamo il controllo.
Ti suona familiare?
Nessun problema, succede a tutti i siti editoriali, soprattutto a quelli ben progettati. È successo anche a me, avevo un blog ben scritto, con una voce chiara, una gerarchia ordinata e una quantità limitata di contenuti. Oggi abbiamo una struttura che contiene centinaia di articoli, guide, post di prodotto, studi, casi e nessuno sa davvero più di cosa parla tutto questo. Abbiamo un menu, abbiamo delle categorie.
Ma non abbiamo una mappa semantica.
Nessuno sa dire: quali sono i temi che trattiamo davvero? Quanti sono? Come si distribuiscono? Ecco perché ho deciso di far parlare il contenuto, letteralmente.
Stai leggendo una nuova edizione del light format del Remarks.
Oggi parliamo di come:
Oggi parliamo di come costruire una mappa semantica del tuo sito usando solo Python, embedding e clustering, per scoprire cosa stai realmente dicendo.
Ti mostro come farlo da zero: senza plugin, senza CMS, senza dashboard pre-impostate.Solo codice, CSV e contenuto. E la demo completa che trovi in fondo a questa edizione e che puoi utilizzare subito su Google Colab.
GO↓
🔵 Clustering Semantico
6 step fondametali.
1/ → Crawl del sito
Ho usato Screaming Frog SEO per estrarre tutte le URL interne.
Impostato il crawl su HTML only
Max 500 URL (se hai il limite versione free),
Esclusi JavaScript rendering, immagini, PDF, parametri.
OUTPUT: un CSV con 3 colonne fondamentali:
URL
Page Title
Meta Description
Poi ho aggiunto via custom extraction anche il primo paragrafo di ogni pagina, dove disponibile. Il contenuto che racconta “di cosa parla davvero” quella pagina.
2/ → Pulizia e standardizzazione
Con Pandas, ho unificato i campi title, description, first_paragraph in un solo campo: text.
E poi ho filtrato:
eliminato tutto ciò che aveva meno di 30 caratteri
rimosse le righe vuote
normalizzato l’encoding
Da qui: 94 URL realmente utili da processare.
3/ → Clustering con TF-IDF + KMeans
Il primo tentativo è stato il più diretto, usare:
TfidfVectorizer di Sklearn con stopword italiane e max_features=500
In sostanza converte i testi in matrici di peso per ogni parola. Ho creato un vettore sparso per ogni pagina, poi ho applicato KMeans, algoritmo che raggruppa i testi in k gruppi, (io ho utilizzato: n_clusters=6) per vedere se emergeva qualcosa.
Clustering veloce, ma basato solo su frequenze di parole.
Ho ridotto la dimensione con PCA (Principal Component Analysis) per visualizzare i risultati in 2D.
Buono per segmentare, ma semantica debole.
I cluster erano spesso mischiati semantici, ma vicini sintatticamente.
4/ → Clustering con BERTopic
Ho alzato l’asticella con BERTopic, un framework che:
Usa Sentence-BERT per tradurre ogni testo in un vettore semantico
Riduce la complessità con UMAP (un algoritmo che mantiene la struttura dei dati)
Raggruppa con HDBSCAN, non ha bisogno di sapere quanti cluster vuoi ottenere
Workflow:
embeddings:
distiluse-base-multilingual-cased-v1
(via sentence-transformers
)
riduzione:
UMAP(n_neighbors=15, min_dist=0.1)
clustering:
HDBSCAN(min_cluster_size=8)
labeling automatico via:
c-TF-IDF
Il risultato sono state due macro-cluster con etichette tematiche estremamente chiare.
Non “categoria”, ma “argomento reale”.Non prodotti
, ma "sostenibilità", "impatto", "dati", "biodiversità"
. Non casi
, ma "comunità", "parco", "fattoria", "progetto"
.
Poi giù di prompting. Si, trovi i template.↓
Referral Program
Se pensi che questo Remarks possa interessare a qualcuno, puoi condividerlo.
5/ → Keyword & Prompting
Per ogni cluster ho:
estratto le 5 parole chiave più rappresentative
Con un CountVectorizer ripulito, stopword + brand
Generato prompt GPT coerenti per:
Articolo SEO
Agisci come un copywriter esperto in [NOME ESPERTO] e digitale. Crea un articolo SEO per il sito [NOME SITO] basato sul seguente topic:
**[inserisci keyword dominante del cluster]**
Obiettivo: [sensibilizzare / informare / convertire].
Il target è: [aziende agricole, famiglie, enti pubblici, ecc.].
Stile: [informativo, emozionale, scientifico, divulgativo].
Struttura: introduzione + 3 paragrafi + CTA finale coerente.
DEM/email
Scrivi una DEM strutturata per chi ha visitato almeno due pagine del sito relative al tema **[nome cluster]**.
Il tono deve essere [empatico e tecnico / emozionale e vicino / formale e autorevole].
Obiettivo: [presentare un’offerta / spingere alla prenotazione di demo / educare].
La CTA va in chiusura ed è contestuale al tema.
Landing page
Crea 5 headline e 5 call to action per una landing page legata al cluster **[nome cluster]**, destinate a utenti nel settore [target].
Devono essere adatte a:
- paid ads
- meta description
- headline hero
Usa un linguaggio semplice, diretto, e differenziante.
Tutti questi prompt sono stati inseriti direttamente nel CSV. Chiunque può prenderlo, filtrare per cluster, e sapere cosa scrivere, per chi, e con quale tono.
6/ → Output operativo
Ho prodotto un CSV che contiene:
URL
Text concatenato
Clustering KMeans
Clustering BERTopic
Etichetta umana del cluster
Top 5 keyword
3 prompt GPT per generare contenuto nativo
Chiunque può usare questo file per:
generare contenuti coerenti in AI
creare campagne adv con gruppo semantico
segmentare utenti per contenuti letti
fare analisi SEO sulle aree tematiche più sviluppate o scoperte
costruire una dashboard che non mostra più “quanto”, ma cosa
Tool che ho utilizzato
Screaming Frog SEO Spider
Per ottenere un export completo delle pagine HTML e metadati da sito/blogPython + pandas
Per unificare, filtrare e gestire il dataset con precisioneTfidfVectorizer (sklearn)
Per trasformare testi in vettori basati sulla frequenza delle paroleKMeans (sklearn)
Per creare cluster “geometrici” semplici da visualizzareSentenceTransformer
Per ottenere rappresentazioni semantiche (BERT) di ogni testoBERTopic
Per creare clustering avanzati con labeling automatico e interpretabilità realeUMAP
Per comprimere dati complessi in poche dimensioni preservando la strutturaHDBSCAN
Per identificare cluster di contenuti senza fissare un numero a prioriMatplotlib
Per visualizzare i cluster su un piano 2D (via PCA)Google Colab
Ambiente cloud per eseguire tutto senza setup locale
DEMO X Google Colab
# STEP 0 – Installazione pacchetti necessari
!pip install pandas bertopic sentence-transformers umap-learn hdbscan --quiet
# STEP 1 – Upload del file CSV
from google.colab import files
uploaded = files.upload()
# STEP 2 – Carica il dataset
import pandas as pd
# 🔧 Modifica il nome del file se necessario
df = pd.read_csv("NOME_DEL_TUO_FILE.csv") # ← sostituisci con il tuo file
# 🔧 Assicurati che ci sia una colonna chiamata "text"
# Altrimenti costruiscila concatenando title, description, first_paragraph
df['text'] = df['text'].fillna('')
df = df[df['text'].str.len() > 30] # Rimuove righe troppo corte
print("Totale righe dopo pulizia:", len(df))
df.head()
# STEP 3 – Clustering con BERTopic
from bertopic import BERTopic
from sentence_transformers import SentenceTransformer
# 🔧 Puoi sostituire il modello con uno più specifico per la tua lingua
embedding_model = SentenceTransformer("distiluse-base-multilingual-cased-v1")
# Calcola gli embeddings
texts = df['text'].tolist()
embeddings = embedding_model.encode(texts, show_progress_bar=True)
# Crea il modello BERTopic
topic_model = BERTopic(language="multilingual", verbose=True)
topics, _ = topic_model.fit_transform(texts, embeddings)
df['bertopic_cluster'] = topics
# STEP 4 – Estrazione parole chiave per ogni cluster
from sklearn.feature_extraction.text import CountVectorizer
# Lista estesa di stopword
stopwords = [
"di", "e", "che", "il", "la", "con", "un", "una", "per", "su", "in", "del", "della",
"dell", "le", "i", "gli", "al", "all", "lo", "non", "più", "come", "anche", "può",
"a", "da", "se", "sono", "tra", "fra", "quando", "dove", "questo", "quello",
"and", "the", "it", "is", "on", "of", "at", "by"
]
# Funzione per estrarre parole chiave pulite
def extract_keywords(texts, stopwords, top_n=5):
vectorizer = CountVectorizer(stop_words=stopwords, max_features=100)
X = vectorizer.fit_transform(texts)
keywords = vectorizer.get_feature_names_out()
freqs = X.sum(axis=0).A1
sorted_keywords = sorted(zip(keywords, freqs), key=lambda x: x[1], reverse=True)
return [kw for kw, _ in sorted_keywords[:top_n]]
# Mappa cluster → keyword
cluster_keywords = {}
for cluster in df['bertopic_cluster'].unique():
texts_in_cluster = df[df['bertopic_cluster'] == cluster]['text']
cluster_keywords[cluster] = ", ".join(extract_keywords(texts_in_cluster, stopwords))
df['bertopic_keywords'] = df['bertopic_cluster'].map(cluster_keywords)
# STEP 5 – Generazione dei Prompt GPT per ogni riga
def generate_prompt(topic_keywords, cluster_id):
return {
"prompt_article": f"Crea un articolo SEO per il sito [inserisci brand] sul tema: {topic_keywords}. Target: [persona]. Obiettivo: [informare/conversione].",
"prompt_email": f"Scrivi una DEM/email destinata a utenti che leggono contenuti sul tema: {topic_keywords}. CTA: [scarica guida / richiedi demo].",
"prompt_landing": f"Genera 5 headline e 5 CTA coerenti con il cluster {cluster_id}, tema: {topic_keywords}. Target: [segmento]."
}
prompts = df.apply(lambda row: generate_prompt(row['bertopic_keywords'], row['bertopic_cluster']), axis=1)
df['prompt_article'] = prompts.apply(lambda x: x['prompt_article'])
df['prompt_email'] = prompts.apply(lambda x: x['prompt_email'])
df['prompt_landing'] = prompts.apply(lambda x: x['prompt_landing'])
# STEP 6 – Esporta il CSV finale
df.to_csv("output_clustering_semantico.csv", index=False)
from google.colab import files
files.download("output_clustering_semantico.csv")
Ora il contenuto parla. Ogni pagina ha un tema. Ogni tema ha una voce. Ogni voce è attivabile: in SEO, in DEM, in Adv, in AI. E lo capisco senza leggere i 94 URL.
Questa è la differenza tra pubblicare e comprendere.
Questo è Remarks. Il Touchpoint digitale di Catobi. Se ti fa piacere continuare a parlare di questi temi, basta scrivermi → In questo canale offriamo spazio, attraverso varianti pubblicitarie, al racconto dell’innovazione dei nostri Partner, e veicolando il contenuto su tutte le nostre piattaforme, comprese LinkedIn, Instagram e Telegram. Qui tutte le informazioni su come sponsorizzare gli episodi della newsletter→