🇮🇹 Italiano | 🇬🇧 English
Trasforma qualsiasi URL in Markdown pulito, deduplicato e pronto per Obsidian — rendering con Chrome headless + estrazione Defuddle, poi una passata opzionale di recupero via LLM. Nessuna estensione del browser richiesta.
Un toolkit Node.js che riproduce — e migliora — l'Obsidian Web Clipper ufficiale, da
riga di comando. Gli dai un URL; lui rende la pagina col Chrome che hai già installato,
toglie il rumore e scrive un .md con frontmatter in una cartella a tua scelta — pronto da
mettere in un vault Obsidian o da dare in pasto a un LLM.
È deliberatamente agnostico rispetto al sito: nessun selettore o scraper specifico per sito. Ogni regola si aggancia a pattern web universali (ruoli ARIA, marcatori di classe delle librerie di carousel, stili calcolati, dati strutturati), così lo stesso codice funziona su uno store Shopify, un blog o una scheda prodotto senza casi speciali.
È anche portabile: copia la cartella clipper/ in qualsiasi progetto, puntala alla tua
cartella di output (una variabile d'ambiente, un flag o un file di config) e parte — Windows,
macOS o Linux, senza modifiche al codice.
- I due modi per usarlo
- Come funziona (la pipeline ibrida)
- Avvio rapido
- Uso
- Configurazione
- Uso responsabile
- Portarlo in un altro progetto / vault
- Formato di output
- I componenti (file per file)
- Confronto con le alternative
- Risoluzione problemi
- Requisiti
- Limitazioni
- Roadmap · Contribuire · Licenza
Ci sono due livelli. Puoi fermarti al livello 1 — è completamente deterministico, gratuito e non richiede alcun LLM.
| Livello | Cosa gira | Cosa ottieni | Costo |
|---|---|---|---|
| 1. Deterministico | node clip.mjs <url> |
Un .md pulito + un sidecar di "candidati" (testo visibile che l'estrattore ha scartato) |
Gratis, offline, adatto a run non presidiati |
| 2. Ibrido (consigliato) | La skill /clip: livello 1 + un giudice LLM che recupera i contenuti davvero in-topic scartati per errore, poi un controllo qualità |
Lo stesso .md, ma più completo — con righe di specifiche, didascalie di feature, ecc. recuperate |
Qualche chiamata LLM (in cache) |
Il livello 2 esiste perché nessuno scraper deterministico può decidere "contenuto vero vs
clutter" su ogni sito — serve giudizio. Così il livello 1 va sul sicuro (non inventa mai),
raccoglie in un sidecar tutto ciò di cui non era certo, e il livello 2 lascia che un LLM
si pronunci su quegli scarti. Il .md di base è sempre valido di per sé; il giudice si
limita ad aggiungere.
┌──────────────────────── LIVELLO 1 (deterministico, clip.mjs) ────────────────────────┐
URL ──▶ │ Chrome headless → settle/idratazione → chiusura cookie → autoscroll → espansione │
│ collassati → estrazione Defuddle (strategia A/C + prune R1–R5) → scrive .md pulito + │
│ livello commerciale JSON-LD │
└───────────────┬──────────────────────────────────────────────────────┬───────────────┘
│ │
raw/<nome>.md (fonte di verità) clipper/.candidates/<nome>.json
│ (blocchi visibili scartati da Defuddle)
│ │
┌───────────────┴──────────────── LIVELLO 2 (ibrido, skill /clip) ───────┴───────────────┐
│ clip-judge (LLM) tiene/scarta ogni candidato per rilevanza rispetto all'argomento │
│ → merge-candidates.mjs ricuce i keep nel .md (deterministico) │
│ → lint-clip.mjs (check gratuiti) → clip-inspector (LLM) solo se il lint segnala │
│ → verdetti in cache per hash del contenuto, così i re-clip costano quasi nulla │
└────────────────────────────────────────────────────────────────────────────────────────┘
│
raw/<nome>.md (ora completo)
- Chrome headless.
puppeteer-coreavvia il Chrome che hai installato (nessun download incorporato) a 1366×900. - Naviga + settle. Carica su
domcontentloaded(molti store tengono aperte socket di analytics, quindinetworkidlenon scatta mai), aspetta un'ancora di contenuto, poi una attesa anti-skeleton: campiona la pagina finché non resta alcun elemento skeleton/shimmer/aria-busye il testo del body è stabile, con un tetto duro di 8s. - Classifica la pagina. Gli interstitial anti-bot (Cloudflare "Just a moment…",
DataDome, "Access Denied") vengono rifiutati con un errore chiaro — non si scrive
nulla, nessuna evasione. I soft-paywall si clippano ma vengono segnalati
(
meta.paywall: true). - Chiude cookie/consenso. CMP noti (OneTrust, Cookiebot, Didomi) più un fallback testuale rigoroso che clicca solo veri pulsanti di consenso. Un guard-rail ripristina la pagina se un click porta altrove.
- Autoscroll + cattura liste virtualizzate. Un
MutationObserverinstallato per primo registra il testo dei nodi aggiunti durante lo scroll, così le righe che le liste virtualizzate (react-window & co.) smontano poi non vanno perse. Poi scorre fino in fondo per caricare i contenuti lazy e torna su. - Espande i contenuti collassati. Apre i
<details>chiusi, clicca i toggle accordionaria-expanded="false"e i pulsanti multilingua "mostra di più" / "carica altro" (it/en/de/fr/es) — fuori da nav/header/footer, mai link, selettori di tab o consenso. È ciò che rende estraibili i valori di specifica nascosti negli accordion. Le tab inattive non vengono cliccate (nasconderebbero quella attiva); i loro pannelli si leggono direttamente dal DOM. - Estrae con Defuddle (A/C + prune R1–R5). Il DOM viene ripulito in modo agnostico — cloni di carousel (R2), contatori a odometro (R3), nodi nascosti a basso testo (R1, preservando i veri contenuti collassati), heading duplicati (R4) — poi Defuddle gira sia sul documento intero (A) sia su una regione a densità massima isolata (C); un punteggio di qualità della prosa sceglie il vincitore. R5 ricuce il testo hero animato parola per parola. Ogni passo di prune è a prova di mutazione (rimozioni idempotenti, isolate) così i re-render SPA non fanno crashare la passata.
- Livello commerciale. Prezzo, disponibilità, valutazione e recensioni si leggono dal
JSON-LD
schema.org(con fallback OpenGraph e microdata nel DOM) in una sezione## Dati commercialietichettata con la fonte reale. - Scrive + misura. Scrive
<outDir>/<nome>.mdcon frontmatter identico al Web Clipper, e un sidecarclipper/.candidates/<nome>.jsoncon i blocchi visibili scartati da Defuddle (per il livello 2) più una metrica di copertura testo (meta.coverage).
Gira solo in modalità ibrida; vedi .claude/skills/clip/SKILL.md.
- Giudizio (agente
clip-judge). Legge il sidecar dei candidati e l'argomento della pagina, e ritornakeep/discardper candidato in base alla rilevanza — tiene titoli/ didascalie/frasi di specifica davvero in-topic, scarta nav, promo, cookie, cross-sell, boilerplate. Nessuna conoscenza specifica del sito. - Merge (
merge-candidates.mjs, deterministico). Ricuce i keep nel.md: sotto un heading corrispondente quando esiste, altrimenti ricostruiti per tag sotto un'unica sezione## Approfondimenti. Deduplica rispetto al testo esistente, marca la provenienza, è idempotente (sicuro da rieseguire). - QA — lint poi inspect.
lint-clip.mjsesegue 11 check deterministici gratuiti (heading orfani, residui "leggi tutto", troncamenti, etichetta-senza-valore, copertura…). Solo se segnala qualcosa entra l'agenteclip-inspector, che ragiona sul risultato e suggerisce recuperi. Lint pulito → zero token extra. - Cache. Ogni verdetto è messo in cache tramite lo SHA-256 del testo del candidato, così ri-clippare la stessa pagina (o una che condivide blocchi) è deterministico e quasi gratuito.
Ogni run del livello 1 emette — best-effort, a costo zero sul .md — un record
diagnostico strutturato in clipper/.diagnostics/ (sidecar per-clip <nome>.diag.json +
registro append-only runs.jsonl): stadi in timeout/errore, copertura, percorso di
estrazione, verdetto boilerplate, paywall/anti-bot, esiti fatali. A fine run — solo in
modalità ibrida e solo se il record segnala errori — la skill /clip invoca l'agente
clip-doctor, che pesa l'errore sullo storico recente (ricorrente vs una-tantum, per
non gridare al lupo su una pagina rotta isolata) e propone fix agnostici ranked (codice o
prompt di un agente), mappati sulla tassonomia di SELF-IMPROVE.md.
Nulla viene applicato senza ok esplicito dell'utente: l'implementazione passa dal
workflow verify+review (nessuna riscrittura silenziosa, nessun auto-commit). In
--deterministic-only la diagnostica si scrive comunque, ma l'agente non gira. Il toggle è
CLIP_DIAGNOSTICS (attivo di default).
cd clipper
npm install
node clip.mjs "https://example.com/un-articolo"
# → scrive ../raw/<Titolo Articolo>.md (e clipper/.candidates/<Titolo Articolo>.json)Questo è il livello deterministico. Per il livello ibrido, esegui la skill /clip dalla
tua sessione Claude Code invece di chiamare clip.mjs direttamente (orchestra il giudice, il
merge e la QA per te).
node clip.mjs <url> ["nome file esplicito senza .md"] [--out <dir>]- Con un nome esplicito, il clip viene scritto in
<outDir>/<nome>.md. - Altrimenti il titolo della pagina viene sanitizzato nel nome file, esattamente come fa il Web Clipper.
--out <dir>sovrascrive la cartella di output per questo run (vedi Configurazione).
Tramite lo script npm:
npm run clip -- <url> ["nome file"]Il tool stampa esattamente dove ha scritto, così gli script (e la skill /clip) possono
catturare i path invece di indovinarli:
Scritto: <path assoluto del .md>
candidati emessi: <N> -> <path assoluto del sidecar dei candidati>
In una sessione Claude Code:
/clip <url> [nome] # estrai + giudica + merge + QA
/clip <url> [nome] --deterministic-only # solo .md di base, nessun LLM (costo zero)
PowerShell — un URL per riga in urls.txt:
Get-Content urls.txt | Where-Object { $_ -and -not $_.StartsWith('#') } | ForEach-Object {
node clip.mjs $_
}bash:
grep -v '^#' urls.txt | while read -r url; do [ -n "$url" ] && node clip.mjs "$url"; doneOgni URL viene clippato in un proprio avvio di Chrome; il browser viene sempre chiuso in un
blocco finally, così una pagina che fallisce non lascia mai un processo appeso né blocca il
resto del batch.
Nulla è obbligatorio — i default funzionano. Tutto ciò che segue è opzionale e a livelli:
flag CLI > variabile d'ambiente > clipper.config.json > default interno.
| Metodo | Esempio | Path risolto rispetto a |
|---|---|---|
| Flag CLI | node clip.mjs <url> --out "D:/MioVault/raw" |
cartella di lavoro corrente |
| Variabile d'ambiente | CLIP_OUT_DIR="D:/MioVault/raw" |
cartella di lavoro corrente |
| File di config | "outDir": "../raw" in clipper.config.json |
la cartella clipper/ |
| Default | (nessuno impostato) → ../raw |
la cartella clipper/ |
Il default ../raw significa: la cartella raw/ accanto a clipper/. Quindi se tieni
clipper/ come sottocartella del tuo vault, i clip finiscono in <vault>/raw/ senza alcuna
configurazione.
| Metodo | Esempio |
|---|---|
| Variabile d'ambiente | CHROME_PATH="/usr/bin/google-chrome" (oppure PUPPETEER_EXECUTABLE_PATH) |
| File di config | "chromePath": "/usr/bin/google-chrome" |
| Auto-discovery | (nessuno impostato) → path noti per il tuo OS (Windows/macOS/Linux), poi channel:'chrome' di puppeteer |
Serve impostarlo solo se Chrome è installato in un percorso non standard. Su un'installazione normale viene trovato automaticamente su tutti e tre gli OS.
Il clipper renderizza pagine web non fidate, quindi adotta alcune difese di default:
- Sandbox di Chrome ATTIVO. Il processo renderer (che esegue il codice della pagina) gira
dentro il sandbox del sistema operativo. Se un ambiente particolare (es. container/CI eseguito
come root) impedisce l'avvio del sandbox, lo si può disattivare in modo esplicito:
CLIP_NO_SANDBOX=1. Su un normale desktop non va disattivato. - Solo URL http/https. Schemi come
file:,data:,chrome:,view-source:sono rifiutati, così il clipper non può leggere file locali o risorse non-web.localhoste gli IP interni restano ammessi (uso locale legittimo).
| Variabile d'ambiente | Effetto |
|---|---|
CLIP_NO_SANDBOX=1 |
Disattiva il sandbox di Chrome (opt-in per container/CI root). Default: sandbox attivo. |
CLIP_STAGE_TIMEOUT_MS=<ms> |
Timeout hard per ogni stadio della pipeline (chiusura cookie, scroll, espansione, guard-rail). Impedisce gli hang quando un iframe/promise non si risolve mai (tipico con URL carichi di parametri ads: gclid/utm_*/gad_*). È una rete di sicurezza contro gli hang da minuti, non una soglia stretta: sta sopra lo stadio legittimo più lento (l'autoscroll su pagine molto lunghe). Default: 180000. |
CLIP_DIAGNOSTICS=0 |
Disattiva la scrittura della diagnostica per-run (registro di automiglioramento). Default: attiva (best-effort, non altera l'output .md né rallenta il clip). |
CLIP_DIAG_DIR=<dir> |
Cartella del registro diagnostica. Default: clipper/.diagnostics. |
Copia clipper.config.example.json in clipper.config.json e modificalo. Tutti i campi sono
opzionali:
clipper.config.json è ignorato da git (è specifico dell'utente/macchina); versiona solo il
file .example.
Il clipper scarica e converte contenuti pubblicati da terzi. Sei tu responsabile del rispetto
dei Termini di Servizio, del robots.txt e del copyright dei siti che clippi. Il tool è
pensato per uso locale e interattivo: non esporlo come servizio di rete — gli URL verso
localhost e gli IP interni sono ammessi by design proprio perché il modello d'uso è la
tua macchina, avviato da te. Le pagine protette da anti-bot vengono rifiutate con un
errore, mai aggirate.
Il clipper è pensato per essere copiato. Ecco tutto ciò che serve sapere — basato su come funziona davvero Obsidian, non su supposizioni.
1. Cos'è "un vault Obsidian". Un vault è semplicemente una cartella su disco. Obsidian
la osserva: nel momento in cui un file .md compare al suo interno, Obsidian lo indicizza
automaticamente — link, backlink, tag e properties del frontmatter inclusi. "Obsidian
aggiorna automaticamente il vault per stare al passo con qualsiasi modifica esterna." →
Non c'è alcun comando di "ingest" o "aggiornamento" da lanciare. Scrivere il file nella
cartella del vault È l'intera procedura.
2. Quindi portarlo è una sola impostazione. Punta outDir a una cartella dentro il vault
di destinazione (es. <vault>/raw o <vault>/Clippings). Tre modi equivalenti:
# a) tieni clipper/ come sottocartella del vault — zero config, usa il default ../raw
# b) variabile d'ambiente:
CLIP_OUT_DIR="/percorso/al/Vault/Clippings" node clipper/clip.mjs <url>
# c) file di config: imposta "outDir" in clipper.config.json3. Passi per inserirlo in un nuovo progetto:
- Copia la cartella
clipper/. (Per il livello ibrido, copia anche.claude/skills/clip/e.claude/agents/clip-judge.md+clip-inspector.md.) cd clipper && npm install.- Imposta
outDir(o affidati al default../raw). ImpostaCHROME_PATHsolo se serve. - Esegui
node clip.mjs <url>— fatto.
4. Cosa non è incluso, di proposito. Il compito del clipper finisce con "un .md
pulito nella tua cartella". Trasformare quei clip in pagine wiki strutturate (riassumere,
creare cross-link, aggiornare un indice) è logica specifica del tuo progetto — cambia da
vault a vault ed è tenuta deliberatamente fuori da questo pacchetto, così il clipper resta
agnostico e riutilizzabile.
5. Opzionale: la CLI ufficiale di Obsidian. Obsidian offre un comando ufficiale obsidian
(Obsidian 1.12.7+, abilitalo in Impostazioni → Generali). Può aprire una nota, impostare
properties, cercare, ecc. — mirando a un vault per nome (obsidian vault="Mio Vault" open file="…") o per la cartella di lavoro del terminale. Richiede che Obsidian sia in
esecuzione e non è necessario per far comparire un clip (vedi punto 1). Il campo vault
nel config è riservato a una futura integrazione opzionale; oggi il clipper si limita a
scrivere il file.
Ogni file si apre con un blocco YAML il cui ordine dei campi e le regole di rendering combaciano esattamente col template di default dell'Obsidian Web Clipper:
---
title: "<titolo>"
source: "<URL completo compresa la query string>"
author:
- "[[<autore>]]" # wikilink; oppure `author:` nudo quando Defuddle non ne trova
published: 2026-06-20 # data, senza virgolette; `published:` nudo se vuoto
created: 2026-06-30 # data odierna al momento del clip
description: "<descrizione>"
tags:
- "clippings"
---
<corpo Markdown estratto>Regole di rendering (riprodotte dal Web Clipper):
- testo (
title,source,description):key: "value", virgolette interne con escape;key:nudo quando vuoto. - wikilink (
author): lista a blocco con un solo elemento- "[[value]]"(nodo collegabile nel grafo Obsidian anziché testo semplice);author:nudo quando vuoto. Autori multipli non vengono separati euristicamente: l'intera stringa diventa un unico target del wikilink. - data (
published,created):YYYY-MM-DDsenza virgolette;key:nudo se vuoto. - multitesto (
tags): lista a blocco, ogni voce- "value".tagsè letteralmenteclippings. source= URL completo con query string (viene rimosso solo il frammento#:~:text=…).created= oggi al runtime.published= il primo segmento del valore di Defuddle.
Il corpo è il Markdown Defuddle della strategia vincente, ripulito da R1–R5, con le immagini
preservate come . La struttura editoriale (heading, feature, tabelle di
specifiche, recensioni) è mantenuta; navigazione, chrome dei cookie, cloni di carousel e testo
frammentato sono rimossi.
## Approfondimenti(solo ibrido) — blocchi in-topic che l'estrattore aveva scartato e il giudice ha promosso, ricostruiti in ordine di lettura. Presente solo quando il giudice recupera contenuto orfano.## Dati commerciali— aggiunta solo quando esistono dati strutturati: prezzo, prezzo di listino, valuta, disponibilità, valutazione aggregata, numero di recensioni e una tabella per recensione — da JSON-LD (con fallback OpenGraph / microdata), con una nota di provenienza che indica la fonte.
| File | Ruolo | Esegue |
|---|---|---|
clip.mjs |
L'estrattore deterministico. URL → .md pulito + sidecar candidati. |
Node CLI |
merge-candidates.mjs |
Merge deterministico dei keep del giudice nel .md. Idempotente. |
Node CLI |
lint-clip.mjs |
11 check gratuiti di completezza/qualità sul .md finale. Output --json. |
Node CLI |
score-clip.mjs |
Valuta un .md rispetto a una checklist di stringhe attese (benchmark). |
Node CLI |
ocr.mjs |
Scaffold per l'OCR del testo incorporato nelle immagini. Non ancora cablato in clip.mjs. |
Node (WIP) |
.claude/agents/clip-judge.md |
Agente LLM: tiene/scarta i candidati per rilevanza. Agnostico. | Claude Code |
.claude/agents/clip-inspector.md |
Agente LLM: ragiona sul clip finale per lacune di completezza. | Claude Code |
.claude/agents/clip-doctor.md |
Agente LLM: diagnostica gli errori di un run e propone fix agnostici ranked. Non applica. | Claude Code |
.claude/skills/clip/SKILL.md |
Orchestra la pipeline ibrida (estrai → giudica → merge → QA → cache → self-improve). | Claude Code |
SELF-IMPROVE.md |
Tassonomia agnostica dei failure-mode → classe di rimedio ammesso. | Doc |
Generati a runtime (ignorati da git): .candidates/ (sidecar + verdetti), .judge-cache/
(verdetti content-addressed), .ocr-cache/, .diagnostics/ (record per-run + registro runs.jsonl).
Esempi CLI standalone:
node lint-clip.mjs "../raw/Mio Clip.md" "clipper/.candidates/Mio Clip.json" --json
node merge-candidates.mjs "../raw/Mio Clip.md" ".candidates/Mio Clip.json" ".candidates/Mio Clip.verdicts.json" "../raw/Mio Clip.md"Confronto illustrativo su un singolo caso reale (scheda prodotto, luglio 2026): non è un benchmark sistematico.
Basato su un audit a 3 vie della stessa scheda prodotto (Dreame L50). Questo clipper ha prodotto l'unico output strutturato e deduplicato (~535 righe utili) contro le ~1925 righe di Apify e le ~2678 di Firecrawl, che includono anche navigazione, script e markup non editoriale.
| Capacità | Web Clipper CLI (questo) | Obsidian Web Clipper (ufficiale) | Apify | Firecrawl |
|---|---|---|---|---|
| Motore | Chrome headless + Defuddle + recupero LLM | Estensione in-browser + Defuddle | Crawler cloud | Crawler cloud + LLM |
| Render JS / idratazione | Sì (autoscroll + settle) | Sì (la tua tab live) | Sì | Sì |
| Recupera il contenuto scartato dall'estrattore | Sì (giudice sui candidati) | No | No | No |
| Rumore / dedup | Forte (R1–R5, scorer A/C) | Moderato | Non prevista (output integrale) | Non prevista (output integrale) |
| Frontmatter | Sì, identico al Web Clipper | Sì | No | No |
| Livello commerciale (prezzo/valutazione/recensioni) | Sì (JSON-LD + microdata) | No | Solo nell'output integrale, non strutturato | Solo nell'output integrale, non strutturato |
| QA di completezza (lint + inspector) | Sì | No | No | No |
| Gira headless / non presidiato | Sì | No (serve la UI del browser) | Sì (cloud) | Sì (cloud) |
| OCR (testo nelle immagini) | Pianificato | No | No | Parziale |
| Costo | Gratis / locale (+ LLM se ibrido) | Gratis | SaaS a pagamento | SaaS a pagamento |
Firecrawl e Apify includono i dati commerciali perché restituiscono la pagina integrale. Questo progetto recupera gli stessi dati in forma strutturata (JSON-LD) e usa un LLM per recuperare il contenuto editoriale che una passata deterministica scarta — mantenendo l'output essenziale.
| Sintomo | Causa | Soluzione |
|---|---|---|
Could not find Chrome / avvio fallito |
Chrome non in un path standard | Imposta CHROME_PATH (o chromePath nel config) sull'eseguibile Chrome/Chromium. |
PAGINA BLOCCATA da anti-bot e nulla scritto |
La pagina è dietro una sfida anti-bot (Cloudflare, DataDome…) | Per scelta — nessuna evasione. Clippala a mano da una sessione browser reale. |
| Clip scritto ma scarno; warning sul paywall | Soft-paywall rilevato (meta.paywall: true) |
Il testo visibile può essere solo l'anteprima gratuita. Nulla di più è recuperabile senza login. |
copertura testo: NN% bassa |
Molta pagina è media, virtualizzata o dietro interazioni | Usa la modalità ibrida: il giudice recupera i candidati scartati. Controlla il sidecar per vedere cosa è stato raccolto. |
| Clip degenerato in boilerplate cookie/consenso | Il muro di consenso non è stato chiuso | Lo script rifiuta di scriverlo (esce con codice non-zero). Riprova, o clippa a mano. |
| Valori di specifica mancanti su una scheda prodotto | Erano dentro un accordion/tab collassato | Già gestito da expandCollapsed + harvest tab nascoste; se ancora manca, il valore è probabilmente reso solo dopo un click che il tool evita — controlla il sidecar dei candidati. |
clipper.config.json ignorato (JSON non valido) |
JSON del config malformato | Correggi il JSON; nel frattempo il tool usa i default. |
| Cartella di output sbagliata | C'è un override attivo | Ricorda la precedenza: --out > CLIP_OUT_DIR > clipper.config.json > ../raw. |
Schema non consentito |
Hai passato un URL non http/https (file:, data:, …) |
Per sicurezza sono ammessi solo http/https. Per leggere un file locale, servilo via un server http. |
| Chrome non parte in un container/CI (root) | Il sandbox non si avvia come root | Imposta CLIP_NO_SANDBOX=1 (opt-in). Su desktop lascia il sandbox attivo. |
| Il clip si blocca a lungo su "Chiusura banner cookie…" (o un altro stadio) | Un iframe/promise di quello stadio non si risolve mai — tipico con URL pieni di parametri di tracking (gclid/gbraid/utm_*/gad_*) che caricano iframe pubblicitari |
Ogni stadio ha ora un timeout hard: regola CLIP_STAGE_TIMEOUT_MS (default 180000 ms). In genere basta ri-clippare con l'URL pulito, senza parametri di tracking. |
- Node.js ≥ 22.12 (sviluppato su Node v24, npm 11).
- Google Chrome o Chromium installato. Trovato automaticamente su Windows/macOS/Linux;
sovrascrivi con
CHROME_PATHse è in un percorso non standard. - Qualsiasi OS — Windows, macOS, Linux.
Dipendenze pinnate: puppeteer-core@25.1.0, defuddle@0.19.0, jsdom@^25.
puppeteer-core (non puppeteer) è una scelta deliberata: pilota il Chrome che hai già
installato e non scarica alcun binario del browser.
- Il livello commerciale ha bisogno di dati strutturati. Prezzo/valutazione/recensioni
vengono da JSON-LD, OpenGraph o microdata
itemprop; pagine che non ne espongono nessuno non producono## Dati commerciali. - Niente OCR. Il testo incorporato nelle immagini non viene ancora letto (scaffold in
ocr.mjs). - Niente trascrizione video. I video sono tenuti solo come link/thumbnail.
- Le pagine molto commerciali mantengono un po' di chrome d'acquisto. La base deterministica è la fonte di verità e non viene mai potata a posteriori; alcune sezioni promo/permuta possono restare. Il giudice si limita ad aggiungere i contenuti scartati; la potatura della base è in roadmap.
- Le pagine anti-bot vengono rifiutate, non aggirate (per scelta).
- I metadati dipendono dalla pagina. Su siti molto dinamici
author/publishedpossono risultare vuoti — comportamento atteso, identico al Web Clipper. - Le SPA con DOM molto instabile restano imprevedibili. Su pagine il cui contenuto cambia struttura da una sessione all'altra (feed raccomandati, varianti A/B, ordine dei commenti), l'euristica generica di isolamento del contenuto principale può occasionalmente agganciare la sezione sbagliata. Non esiste un rimedio agnostico affidabile al 100% per questi casi — selettori specifici del sito violerebbero la filosofia del progetto.
Vedi ROADMAP.md. Priorità a breve:
- OCR per il testo incorporato nelle immagini.
- Specifiche come tabelle GFM (da JSON-LD o tabelle HTML).
- Promozione opzionale dei campi commerciali nel frontmatter (Dataview).
Già consegnato: pipeline di recupero ibrida (giudice + merge + QA), livello commerciale (JSON-LD + microdata), espansione contenuti collassati + "mostra di più", harvest tab nascoste e shadow-DOM, discovery Chrome cross-platform, cartella di output configurabile, portabilità.
Issue e PR sono benvenute. Mantieni intatto il principio fondante: le regole devono essere agnostiche rispetto al sito — agganciarsi a pattern web universali (ARIA, marcatori di classe delle librerie, stili calcolati, dati strutturati), mai selettori specifici per sito. Quando aggiungi una regola di pulizia, documenta quale failure mode affronta e perché non può mangiare contenuto legittimo, nello stile di R1–R5, con un esempio prima/dopo su una pagina reale.
MIT — vedi LICENSE.
Obsidian, Defuddle, Puppeteer, Apify, Firecrawl e i prodotti citati come casi di test appartengono ai rispettivi titolari. Progetto indipendente, non affiliato ad alcuno di essi.
{ "outDir": "../raw", // dove vanno i file .md (relativo a clipper/, o assoluto) "chromePath": null, // null = auto-discovery; oppure un path esplicito "vault": null, // riservato per futura integrazione con la CLI ufficiale (vedi sotto) "attachmentsDir": null // riservato per quando sarà cablato il download immagini/OCR }