Visualizzare gli ultimi eventi sismici dal sito INGV (usando OpenStreetMap)

Stamattina un amico (TheDom), studente dell’Università dell’Aquila fortunatamente scampato al terremoto, mi ha chiesto di aiutarlo a creare uno script che si interfacciasse con il sito dell’Istituto Nazionale di Geofisica e Vulcanologia e che visualizzasse i dati degli ultimi eventi sismici e restituisse un link ad OpenStreetMap per visualizzare la cartina.

Guardando il codice dell’homepage del sito mi sono accorto che i singoli eventi erano racchiusi nel tag <tr class=”print_light”> e i dati dell’evento erano racchiusi nei tag figli <td class=”td_events”>.

<tr class="print_light"  [...]>
<td class="td_events">1206577780</td>
<td class="td_events">&nbsp;</td>
<td class="td_events">2009/04/11</td>
<td class="td_events">16:18:34</td>
<td class="td_events">42.264</td>
<td class="td_events" width="45px">13.486</td>
<td class="td_events">9</td>
<td class="td_events">Ml:2.8</td>
<td class="td_events">&nbsp;</td>
<td class="td_events">Valle_dell'Aterno</td>
</tr>


Considerata la regolarità del codice, ho sfruttato le potenti funzionalità del modulo di parsing BeautifulSoup, per raccogliere facilmente i dati dal sito.

Il cuore dello script è costituito dalla funzione DataCollect che, preso il codice della pagina in input, trova tutti i tag che corrispondono a <tr class=”print_light”>. In seguito, cercando all’interno dei singoli tag <tr>, restituisce, sotto forma di lista, il testo contenuto nei tag figli <td>.

def DataCollect(pagina,id):
     """Restituisce una lista con i dati desiderati"""
     lista = []
     dati = pagina.findAll('tr',attrs={"class":"print_light"})[id]
     dati = dati.findAll('td',attrs={"class":"td_events"})
     for i in dati:
     lista.append(i.string)
     return lista


La riga di codice numero 4 trova tutti i tag tr avente gli attributi definiti nel dizionario {“class”:”print_light”} passato come variabile. Considerando che l’istanza findAll dell’oggetto pagina restituisce, sotto forma di tupla, il contenuto dei singoli tag tr, è possibile accedere al contenuto di un solo tag tr usando gli indici della tupla (il numero tra parentesi quadre). Dopodiché è possibile rieseguire una seconda istanza findAll sull’oggetto dati (riga 5), che come abbiamo visto in precedenza contiene solo il contenuto di un solo tag, cercando questa volta tutti i tag td. A questo punto l’oggetto dati è una tupla contenente tutti i tag td, figli del tag tr (quelli mostrati nel codice html precedente). Infine basta iterare all’interno di questa tupla (riga 6), assegnando ad una lista (inizializzata alla riga 3) il contenuto dei signoli tag td ottenuti attraverso l’istanza string (riga 7).

La funziona Parsing legge semplicemente il contenuto della pagina html e lo passa a BeautifulSoup per l’elaborazione.

def Parsing(link):
     """Restituisce il parsing della pagina"""
     try:
         socket = urlopen(link)
         testo = BeautifulSoup(socket.read())
         socket.close()
     except:
         return ("""Si è riscontrato un errore durante l'apertura del link, prima \
         di procedere:\t
         1) controllare la connessione ad internet\t
         2) assicurarsi che il link esista\t
         3) assicurarsi che il link sia scritto correttamente (ricordarsi di scrivere \
         anche http://)\t
         4) controllare i permessi per accedere alla rete.""")
 return testo


Alla riga 5 la funzione apre il link dell’home page dell INGV e alla riga 6 l’istanza read(), che restituisce il contenuto html della pagina, viene passata all’elaboratore BeautifulSoup.

Infine l’ultima funzione, formatta l’output in maniera colorata e più “umana” sfruttando il modulo scritto da Checkm.

def HeartquakePrint(lista):
     """Formatta e stampa i dati dell'evento sismico"""
     print cms.color("<red>Dati riepilogativi evento sismico</red>")
     print cms.color("<green>Link diretto:</green>   <yellow>http://cnt.rm.ingv.it/~earthquake/data_id/%s/event.php</yellow>") % lista[0]
     print cms.color("<green>Data:</green> <yellow>%s</yellow>") % lista[2]
     print cms.color("<green>Ora:</green> <yellow>%s</yellow>") % lista[3]
     print cms.color("<green>Latitudine:</green> <yellow>%s N</yellow>") % lista[4]
     print cms.color("<green>Longitudine:</green> <yellow>%s E</yellow>") % lista[5]
     print cms.color("<green>Link OpenStreetMap:</green> <yellow>http://www.openstreetmap.org/?lat=%s&lon=%s&zoom=17&layers=B000FTF</yellow>") % (lista[4],lista[5])
     print cms.color("<green>Magnitudo:</green> <yellow>%s</yellow>") % lista[7]
     print cms.color("<green>Distretto sismico:</green> <yellow>%s</yellow>\n") % lista[9]

Il modo più semplice per eseguire lo script (sia su windows che su linux) è quello di scaricare l’archivio contenente tutti i file necessari all’esecuzione da qui. Scompattarlo ed eseguirlo digitando in un terminale:

$: python script.py

Questo è il risultato finale:

ingv_screen

Related Posts
Leave a comment ?

11 Comments.

  1. Script 4 Solution » Blog Archive » Il primo spider - pingback on 18 aprile 2009 at 12:39
  2. è sbagliata l’estensione dello script non è script_ingvtar.gz ma script_ingv.tar.gz altrimenti quando lo si decomprime dà errore

  3. Per la sua usabilità, posso suggerire di disporre gli eventi al contrario? Nel senso, che come ultimo terremoto visualizzato ci sia l’ultimo avvenuto?

    Grazie comunque, veramente interessante.

  4. Ho corretto entrambe le cose, grazie ad entrambi. :)

  5. Se per la prima cosa ti sono stato d’aiuto, ti suggerisco un’altra cosa: qualche opzione, una, per esempio, poter filtrare i terremoti sotto una certa soglia?

  6. che ne diresti di una versione che credi un layer su osm che identifichi i terremoti con un circolo di ampiezza proporzionale all’intensità e colore che sbiadisce in funzione inversamente proprorzionale alla prossimità temporale?

    magari da presentare ad OSMit?

  7. @teo: Sto pensando a qualcosa da riga di comando, appena ho un po’ di tempo apro un altro post.

  8. @EdoM: Dico che è una bella idea, ed è anche bello poterla presentare ad OSMit!
    Userei gli openlayer?
    Posso chiedere una mano alla comunità?

  9. Se ti serve una mano ti aiuto più che volentieri.. il lavoro che ho svolto con openlayers lo trovi qui:
    http://piccimario.wordpress.com/2009/04/21/disegnare-una-mappa-dei-terremoti/
    e riguarda proprio i terremoti, dato che è stato questo tuo articolo a darmi l’ispirazione.. il codice è disponibile liberamente, sentiti pure libero di usarlo se ti può aiutare, e non esitare a chiedere se hai qualche dubbio!

  10. Ciao Mario,
    ho guardato il tuo lavoro (complimenti!) e mi ero ripromesso di scriverti al più presto anche perché non conosco il php ne tanto meno il java (per gli openlayers vado a senso…) e in effetti mi piacerebbe chiederti una mano.
    Ti mando una email nei prox giorni per spiegarti il mio progetto.
    Grazie.

Leave a Comment


NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackbacks and Pingbacks: