Per costruire la nostra prima ricetta dobbiamo scegliere efficacemente uno o più selettori. Free e Batch Data Collector prevedono uno strumento per la definizione interattiva dei selettori, ma anche in questo caso la consapevolezza dell’utilizzatore può fare la differenza.
Si inizia sempre con un selettore principale e si prosegue con un selettore per ogni colonna del record da costruire. Per spiegarne l’utilità inventeremo un codice sorgente semplificato che sarà oggetto degli esempi di questo capitolo.
<html> <header> <title>Yearly budget and expenses</title> </header> <body> <div id="firstBlock"> Questa pagina contiene i conteggi aggiornati al <strong>25 settembre 2019</strong> relativi a budget e spese. <span>Budget totale delle iniziative: <i>12.000.000 Euro</i></span><br/> <span>Spese totali delle iniziative: <i>6.000.000 Euro</i></span> </div> <table id="year2017"> <tr><td>Month</td><td>Relative (Euro)</td><td>Absolute (Euro)</td></tr> <tr><td>Jan-Feb</td><td>1.000.000</td><td>1.000.000</td></tr> <tr><td>Mar-Apr</td><td>1.000.000</td><td>2.000.000</td></tr> <tr><td>May-Jun</td><td>1.000.000</td><td>3.000.000</td></tr> <tr><td>Jul-Aug</td><td>1.000.000</td><td>4.000.000</td></tr> <tr><td>Sep-Oct</td><td>1.000.000</td><td>5.000.000</td></tr> <tr><td>Nov-Dic</td><td>1.000.000</td><td>6.000.000</td></tr> </table> <div class="finalcredit">Credito finale: 6.000.000 Euro</div> <br/><br/> <table> <tr><td>Month</td><td>Relative (Euro)</td><td>Absolute (Euro)</td></tr> <tr><td>Jan-Feb</td><td>500.000</td><td>500.000</td></tr> <tr><td>Mar-Apr</td><td>500.000</td><td>1.000.000</td></tr> <tr><td>May-Jun</td><td>500.000</td><td>1.500.000</td></tr> <tr><td>Jul-Aug</td><td>1.000.000</td><td>2.500.000</td></tr> <tr><td>Sep-Oct</td><td>1.000.000</td><td>3.500.000</td></tr> <tr><td>Nov-Dic</td><td>1.000.000</td><td>4.500.000</td></tr> </table> <div class="finalcredit">Credito finale: 1.500.000 Euro</div> <br/> </body>
Il codice genererà una pagina con un contenuto simile al seguente:
Questa pagina contiene i conteggi aggiornati al 25 settembre 2019 relativi a budget e spese.
Budget totale delle iniziative: 12.000.000 Euro
Spese totali delle iniziative: 6.000.000 Euro
Month | Relative (Euro) | Absolute (Euro) |
Jan-Feb | 1.000.000 | 1.000.000 |
Mar-Apr | 1.000.000 | 2.000.000 |
May-Jun | 1.000.000 | 3.000.000 |
Jul-Aug | 1.000.000 | 4.000.000 |
Sep-Oct | 1.000.000 | 5.000.000 |
Nov-Dec | 1.000.000 | 6.000.000 |
Credito finale: 6.000.000 Euro
Month | Relative (Euro) | Absolute (Euro) |
Jan-Feb | 500.000 | 500.000 |
Mar-Apr | 500.000 | 1.000.000 |
May-Jun | 500.000 | 1.500.000 |
Jul-Aug | 1.000.000 | 2.500.000 |
Sep-Oct | 1.000.000 | 3.500.000 |
Nov-Dec | 1.000.000 | 4.500.000 |
Credito finale: 1.500.000 Euro
Il sorgente è piuttosto breve e contiene due tipologie di macro-elementi:
– elementi sfusi sparsi lungo il testo;
– elementi raggruppati, per esempio in tabella o elenco.
Fissare un Blocco principale o elemento ripetitivo per una nuova ricetta consente di definire uno spettro di analisi e visibilità. Se il blocco principale scelto fosse la prima tabella, i campi figli accessibili a partire dal blocco principale sarebbero le sette righe e le ventuno celle della tabella stessa. Nulla di più. E quindi porremmo Free/Batch Data Collector nella condizione di identificare uno o più tag da agganciare (appunto, le righe e le colonne della tabella) tutti figli del tag table scelto.
Per allargare il campo di visibilità a tutta la pagina così da agganciare elementi qua e là bisognerebbe risalire di livello fino ad arrivare, al più, al tag body o addirittura html, padre di tutti i tag. Ma in questo modo dovremmo rinunciare all’identificazione di un elemento ripetitivo.
Il sotto-testo di questa narrazione è che l’identificazione di un elemento padre di tag ripetitivi come Blocco principale diventa necessaria quando si desiderano estrarre più oggetti tra loro omogenei, ad esempio le righe di una tabella o le colonne di una riga, le righe di un elenco puntato, i link all’interno di uno specifico paragrafo, e così via. Fissando con precisione un elemento “Blocco principale o elemento ripetitivo” sarà possibile creare estrazioni per iterazione e quindi collezionare tante righe che strutturalmente si susseguono con sforzi pressoché nulli.
Blocco principale o elemento ripetitivo
(Main or recursive block)
E’ praticamente l’elemento padre da cui partire per scrivere una ricetta. Ha senso identificarlo come differente da html o body soprattutto se si desidera effettuare l’estrazione di una tabella o di un elenco, o comunque di un tag che, posto dentro un altro tag, ricorre più volte.
Nel nostro esempio
table#year2017 tr
è elemento padre di tutte le righe di esso figlie.
Quanto sopra è, insistiamo, un selettore CSS che indica come padre degli oggetti che agganceremo il tag tr posto dentro la table con id year2017.
Colonne della ricetta
(Set columns)
Le colonne di una ricetta possono essere dedicate – è bene ribadirlo – a informazioni sparse lungo la pagina web, oppure a elementi ricorrenti contenuti in un elemento padre. Considerando valido l’esempio sopra, per estrarre tutte le informazioni di ciascuna riga della table year2017 dovremo generare 3 colonne e agganciarle al nodo td con Numero di occorrenze rispettivamente 0, 1 e 2 (la prima, la seconda e la terza).
Ecco l’aspetto della ricetta completa:
Ricapitoliamo dettagliatamente, a costo di eccedere.
Poiché nel nostro esempio le righe da estrarre per la prima delle due tabelle sono tutte figlie dello stesso elemento table, individuiamo il blocco principale o elemento ripetitivo in tr.
La tabella scelta contiene tre colonne, che possono essere ricreate con il tasto “Aggiungi colonna“, posto al fondo dell’area di creazione della ricetta.
Le colonne devono poi essere attivate con l’apposita spunta ubicata a sinistra di ciascuna di esse. Gli elementi da agganciare sono tutti colonne td, pertanto bisognerà digitare td nel campo Nodo. E per riferirsi alla colonna giusta sarà sufficiente agire sul Occorrenza n. (Instance no.).
Il primo tag trovato scorrendo il codice dall’alto ha sempre indice di occorrenza 0. Pertanto gli elementi di interesse avranno indici 0, 1 e 2. Infine, in corrispondenza di Tipo, la selezione dell’opzione testo (text) permetterà di far ritornare solo la stringa visibile sullo schermo.
Una ricetta per estrarre tabelle
Secondo la stessa logica si potrebbe generalizzare una ricetta per estrarre tabelle. Ipotizziamo di voler catturare tabelle di 5 colonne. Il nostro Blocco principale o elemento ripetitivo sarebbe un generico “table tr“.
La ricetta conterrebbe 5 colonne, ciascuna indicante il nodo “td“. I campi Occorrenza n. conterranno i progressivi da 0 a 4.
I più smaliziati avranno già capito che una ricetta così composta catturerebbe righe da tutte le tabelle presenti nel codice sorgente in sequenza, partendo dalla prima, continuando con la seconda e così via fino all’ultima. Non solo: unirebbe tutte le righe in un’unica grande tabella. L’unico limite dimensionale sarebbe il numero di colonne, limitato nell’esempio a 5.
Ovviamente esistono selettori per specificare da quale tag table attingere i dati. Non specificando nulla lo spettro di visibilità sarà più ampio e coinvolgerà tutti i tag table della pagina.
Estrarre dati disomogenei
Sempre con riferimento all’esempio sopra, potremmo voler ottenere una tabella così composta:
Aggiornamento | Budget | Spese | Spese 2018 |
25 settembre 2019 | 12.000.000 Euro | 6.000.000 Euro | 4.500.000 Euro |
Sarebbe quindi necessario raccogliere informazioni da nodi non contigui del codice sorgente. A questo proposito, il Blocco principale o elemento ripetitivo diventerebbe “html” o “body“. Free e Batch Data Collector prevedono anche la possibilità di inserire una parola chiave flessibile che ricerchi automaticamente il blocco principale. Si tratta di “aggressiveScraping“.
Qualunque scelta sia operata in tal senso, bisognerà poi definire quattro colonne, ciascuna con etichetta “Aggiornamento”, “Budget”, “Spese” e “Spese 2018”. I nodi da assegnare, nell’ordine, saranno:
- div#firstBlock strong
per “25 settembre 2019”. - span i
per “12.000.000 Euro”. - span+span i
per selezionare il secondo “span” in ordine di codice, e dunque il tag “i” in esso contenuto, e dunque “6.000.000 Euro”. - table+table tr+tr+tr+tr+tr+tr+tr td+td+td
per selezionare la terza colonna della settima riga della seconda tabella.
Nonostante l’intuitività di questo schema, un po’ simile alla battaglia navale, alcune notazioni possono essere scritte in modo più semplice e conciso. Per esempio, table+table tr+tr+tr+tr+tr+tr+tr td+td+td può anche essere espresso come
table:nth-child(2) tr:nth-child(7) td
e inserendo il numero 2 nel campo Occorrenza n.
nth-child, invece, è un tipico selettore CSS standard e permette rapidamente agganciare qualunque sottonodo altrimenti difficilmente raggiungibile (magari perché non identificato univocamente da un id o che non sia parte di un class).
Di seguito la ricetta nella sua interezza:
Nel prossimo paragrafo introdurremo una lista più completa di selettori CSS rispondendo a piccoli e grandi dilemmi riguardanti la definizione del selettore più opportuno.