Integrazione dati

Introduzione

In questo tutorial parleremo di integrazione di dati, presentando diversi argomenti / tool:

  • OpenStreetMap

  • UMap

  • Formato JSON

  • Web API

In particolare mapperemo degli agritur del Trentino su Umap, seguendo grossomodo il tutorial sugli agritur di CoderDojoTrento. La differenza sostanziale sarà che in questo caso invece dei Google spreadsheet useremo Python.

Scaletta:

  • 0 Presentazione OpenStreetMap e UMap

  • 1 prendere dati agritur da dati.trentino.it

  • 2 leggere file CSV in Python

  • 3 cercare automaticamente coordinate geografiche usando le web api di MapQuest / OpenStreetMap Nominatim

    • parsing formato json

  • 4 scrivere il nuovo file CSV con i campi latitudine e longitudine riempiti

  • 5 importare il file CSV in Umap

  • 6 Inserire la mappa in Jupyter

Che fare

  • scompatta lo zip in una cartella, dovresti ottenere qualcosa del genere:

integration
    integration.ipynb
    integration-sol.ipynb
    jupman.py

ATTENZIONE: Per essere visualizzato correttamente, il file del notebook DEVE essere nella cartella szippata.

  • apri il Jupyter Notebook da quella cartella. Due cose dovrebbero aprirsi, prima una console e poi un browser. Il browser dovrebbe mostrare una lista di file: naviga la lista e apri il notebook integration.ipynb

  • Prosegui leggendo il file degli esercizi, ogni tanto al suo interno troverai delle scritte ESERCIZIO, che ti chiederanno di scrivere dei comandi Python nelle celle successive.

Scorciatoie da tastiera:

  • Per eseguire il codice Python dentro una cella di Jupyter, premi Control+Invio

  • Per eseguire il codice Python dentro una cella di Jupyter E selezionare la cella seguente, premi Shift+Invio

  • Per eseguire il codice Python dentro una cella di Jupyter E creare una nuova cella subito dopo, premi Alt+Invio

  • Se per caso il Notebook sembra inchiodato, prova a selezionare Kernel -> Restart

0 Presentazione OpenStreetMap e UMap

0.1 OpenStreetMap

Conosciamo tutti le Google Maps. Se le usiamo come privati cittadini, sono gratute, ma se siamo delle aziende Google potrebbe porci dei vincoli al riuso - sicuramente per scaricare tutto il database del mondo dovremmo chiedere permessi e pagare soldoni, sempre che Google ce lo conceda ! Esistono alternative? Sappiamo che esiste un enciclopedia realizzata completamente da volontari che si chiama Wikipedia, e per le mappe? Per nostra fortuna esiste OpenStreetMap (detta anche OSM), che è una mappa del mondo realizzata da volontari, completamente gratuita, nonchè scaricabile e riusabile con licenza OpenDatabase License. La licenza è piuttosto libera, il peggio che può capitare è che in alcuni casi si sia costretti a ripubblicare le proprie mappe costruite usando dati presi da OpenStreetMap.

✪ ESERCIZIO 0.1.1: Per capire un po’ come navigare OpenStreetMap, puoi guardare il tutorial di CoderDojo Trento Inseriamo un punto in OpenStreetMap. Non serve che inserisci punti in OpenStreetMap, ma naturalmente se vuoi arricchire la mappa la comunità te ne sarà grata !

✪ ESERCIZIO 0.1.2 Per capire le potenzialità di OpenStreetMap e le differenze con Google Maps, guarda anche queste diverse visualizzazioni di OpenStreetMap che evidenziano alcune categorie di punti che si trovano in OpenStreetMap:

OsmHydrant: Mappa di idranti, notare il raggio d’azione utile degli idranti

WheelMap: mappa dei luoghi accessibili ai disabili

TagInfo Ad ogni oggetto in OpenStreetMap si possono aggiungere tag. TagInfo mostra le tag più utilizzate.

0.1 UMap

UMap è un tool online per creare mappe in cui si sovrappongono punti che vogliamo noi a OpenStreetMap.

✪ ESERCIZIO 0.2.1: Se non l’hai già fatto precedentemente, prova a fare il tutorial di CoderDojo Trento sui Servizi di Rovereto e Umap. E’ molto semplice e non serve Python, basta usare tool online. Mostra come prendere da dati.trentino.it i servizi di Rovereto in formato JSON georeferenziati, convertirli in CSV e importarli in UMap

1 Prendiamoci i dati

Concentriamoci adesso sugli Agritur. Andiamo a cercarci dei dati dal catalogo opendata dati.trentino.it. In questo caso sceglieremo un file dal dataset Agritur del Trentino.

✪ DOMANDA 1.1: Quale è la licenza del dataset? Possiamo farci tutto quello che vogliamo ?

Mostra risposta

Nel dataset troviamo la risorsa Elenco Agritur che al suo interno contiene un link ad un file CSV.

ATTENZIONE: Per questo esercizio, NON usate il CSV dal sito, ma scaricate invece agritur16_10_2014.csv a questo link che come dal nome contiene un file del 2014.

✪ DOMANDA 1.2: notate differenze tra il file del 2014 e quello corrente sul sito ?

Mostra risposta

✪ DOMANDA 1.3: Se realizzaste un programma per leggere questi file degli agriturismi scaricandoli periodicamente dal sito, a lungo andare quali problemi potrebbero insorgere (pensate anche al contenuto del file) ?

Vediamo qua una anterprima del file agritur16_10_2014.csv (NOTA: i campi a destra sono tagliati) :

N_prog;Num_archivio;data_rilascio_prima_autorizzazione;Nome_Impresa_agricola;A ...
1;10;11/11/1986;DALLAGO LUCIANO;no;38060;Aldeno;Via S. D'Acquisto n. 4;29251/9 ...
2;26;16/12/1986;ARMAN CRISTINA;no;38010;Faedo;Loc. Pineta - Maso Nello;137876/ ...
3;37;22/12/1986;INAMA FRANCESCO;no;38010;Sanzeno;Via Casalini n. 74;130041/96; ...
4;49;15/01/1987;MONTIBELLER VALTER;no;38050;Roncegno;Via Prose n. 1;138559/96; ...
Mostra risposta

✪ DOMANDA 1.4: Ci sono le intestazioni ? Qual’è il separatore ?

Mostra risposta

✪ DOMANDA 1.5: Quanti indirizzi ci sono nel file ? Se volessimo posizionare gli agritur su una mappa, quali indirizzi useremmo ? Ci sono le coordinate geografiche?

Mostra risposta

✪ DOMANDA 1.6: Prova ad aprire il file in LibreOffice Calc o Excel, facendo attenzione a specificare i separatori corretti e l’encoding (guarda l’header ‘Società’ , in particolare il carattere finale !)

ATTENZIONE SE USI EXCEL!

Facendo direttamente File->Apri in Excel, probabilmente Excel cercherà di immaginarsi da solo come intabellare il CSV, e sbaglierà metterà tutto le righe in una colonna. Per ovviare al problema, dobbiamo dire ad Excel di mostrare un pannello per chiederci come vogliamo aprire il CSV, facendo così:

  • In Excel vecchi, cerca File-> Importa

  • In Excel recenti, clicca la scheda Dati e poi seleziona Da testo. Per ulteriori riferimenti su Excel, vedere guida di Salvatore Aranzulla

2. Leggiamo il CSV

✪ ESERCIZIO 2.1: Prova a caricare le prime 10 righe del file CSV in Python usando le istruzioni già viste nella capitolo sui formati

Fai attenzione al delimitatore e specifica encoding='utf-8' come parametro nella open !

Per ottenere 10 righe, puoi usare un ciclo while e ottenere ciascuna riga con un istruzione del tipo

row = next(lettore)
Mostra soluzione
[1]:
# scrivi qui


['N_prog', 'Num_archivio', 'data_rilascio_prima_autorizzazione', 'Nome_Impresa_agricola', 'Azienda_zootecnica', 'CAP', 'sede_impresa_agricola', 'indirizzo_impresa_agricola', 'CCIAA', 'pref', 'tel', 'società', 'malga', 'PEC', 'indirizzo_e_mail', 'Altitudine', 'Latitudine', 'Longitudine', 'Comune_Sede_Agriturismo', 'Indirizzo_agriturismo', 'Denominazione_Agriturismo', 'N_appartamenti', 'N_stanze_in_appartamento', 'Tot_posti_letto_in_appartamento', 'N_bagni_appartamento', 'N_Stanze', 'Tot_posti_letto_in_stanze', 'N_bagni_in_stanze', 'N_tot_stanze_e_stanze_in_appartamento', 'Tot_posti_letto', 'Alloggio_in_appartamenti', 'Alloggio_in_stanze', 'Prima_colazione', 'Ristorazione_solo_per_alloggiati', 'Servizio_Ristorante_per_passanti', 'N_posti_tavola_interni_a_struttura', 'N_posti_tavola_esterni_alla_struttura', 'N_tot_posti_tavola', 'N_tot_Bagni', 'Agricampeggio', 'N_piazzole', 'N_tot_posti_in_campeggio', 'Fattoria_didattica', 'Altre_attività_ricreative', 'Degustazione', 'Classificazione_punteggio_tabella_1', 'Classificazione_punteggio_tabella_2', 'Classificazione_punteggio_tabella_3', 'ASSEGNAZIONE_MARGHERITE']
['1', '10', '11/11/1986', 'DALLAGO LUCIANO', 'no', '38060', 'Aldeno', "Via S. D'Acquisto n. 4", '29251/97', '0461', '842629', 'no', 'no', 'luciano.dallago@pec.agritel.it', 'gastone.dallago@smach.it ', '810', '', '', 'Garniga Terme', 'Loc. al Lago n. 15', 'DALLAGO LUCIANO', '2', '5', '10', '2', '0', '0', '0', '5', '10', 'si', 'no', 'no', 'no', 'no', '0', '0', '0', '0', 'no', '0', '0', 'no', '', 'no', '0', '0', '0', '']
['2', '26', '16/12/1986', 'ARMAN CRISTINA', 'no', '38010', 'Faedo', 'Loc. Pineta - Maso Nello', '137876/96', '0461', '650384', 'no', 'no', 'cristina.arman@pec.agritel.it', 'masonello@hotmail.com ', '595', '', '', 'Faedo', 'Loc. Pineta - Maso Nello', 'MASO NELLO', '1', '2', '4', '1', '4', '8', '4', '6', '12', 'si', 'si', 'si', 'no', 'si', '30', '0', '30', '1', 'no', '0', '0', 'si', '', 'si', '31', '40', '10', '3']
['3', '37', '22/12/1986', 'INAMA FRANCESCO', 'no', '38010', 'Sanzeno', 'Via Casalini n. 74', '130041/96', '0463', '434072', 'no', 'no', 'inama.francesco@cia.legalmail.it', '', '641', '', '', 'Sanzeno', 'Via Casalini n. 74', 'ANAUNIA', '0', '0', '0', '0', '5', '10', '5', '5', '10', 'no', 'si', 'si', 'no', 'no', '0', '0', '0', '0', 'no', '0', '0', 'no', '', 'no', '22', '19', '6', '2']
['4', '49', '15/01/1987', 'MONTIBELLER VALTER', 'no', '38050', 'Roncegno', 'Via Prose n. 1', '138559/96', '0461', '773349', 'no', 'no', 'AZ.MONTIBELLER@PEC.IT', '', '535', '', '', 'Roncegno', 'Via Prose n. 1', 'MONTIBELLER', '6', '6', '8', '6', '4', '8', '4', '10', '16', 'si', 'si', 'si', 'no', 'si', '43', '0', '43', '2', 'si', '15', '30', 'si', 'bagni di fieno', 'si', '32', '24', '10', '2']
['5', '52', '20/01/1987', 'BRESCIANI ITALO', 'no', '38060', 'Tenno', 'Via Diaz n. 40 - Fraz. Cologna', '138928/96', '0464', '521701', 'no', 'no', 'italo.bresciani@pec.agritel.it', '', '428', '', '', 'Tenno', 'Loc. Fontanelle', 'PIZACOL DI BRESCIANI ITALO', '0', '0', '0', '0', '0', '0', '0', '0', '0', 'no', 'no', 'no', 'no', 'si', '35', '0', '35', '2', 'no', '0', '0', 'no', '', 'no', '7', '11', '2', '2']
['6', '61', '30/01/1987', 'FONTANARI ETTORE', 'no', '38057', 'Pergine Valsugana', 'Via Chimelli n. 25', '38575/97', '0461', '530023', 'no', 'no', 'ettore.fontanari@pec.agritel.it', '', '482', '', '', 'Pergine Valsugana', 'Via Chimelli n. 25', 'FONTANARI ETTORE', '4', '6', '9', '4', '0', '0', '0', '6', '9', 'si', 'no', 'no', 'no', 'no', '0', '0', '0', '0', 'no', '0', '0', 'no', '', 'no', '8', '14', '4', '2']
['7', '68', '30/01/1987', 'MARINCONZ GINO', 'no', '38010', 'Coredo', 'Via G. Inama n. 21', '61840/97', '0463', '536328', 'no', 'no', 'GINO.MARINCONZ@PEC.IT', '', '831', '', '', 'Coredo', 'Via G. Inama n. 21', 'MARINCONZ GINO', '3', '6', '11', '3', '0', '0', '0', '6', '11', 'si', 'no', 'no', 'no', 'no', '0', '0', '0', '0', 'no', '0', '0', 'no', '', 'no', '9', '12', '4', '2']
['8', '74', '06/02/1987', 'BERNARDI ARMANDA BORTOLOTTI', 'no', '38057', 'Pergine Valsugana', 'Via Montesei n. 2', '141055/96', '0461', '530125', 'no', 'no', 'AGRITUR.BORTOLOTTI@PEC.CGN.IT', 'agritur.bortolotti@tin.it', '482', '', '', 'Pergine Valsugana', 'Via Montesei n. 4', 'AGRITUR BORTOLOTTI', '2', '2', '8', '2', '6', '14', '6', '8', '22', 'si', 'si', 'si', 'no', 'si', '25', '0', '25', '2', 'no', '0', '0', 'si', '', 'no', '31', '26', '11', '3']
['9', '94', '06/05/1987', 'ZAMBONI PIA', 'no', '38040', 'Bosentino', 'Maso Fosina n. 5', '129820/96', '0461', '848468', 'no', 'no', 'pia.zamboni@pec.agritel.it', '', '700', '', '', 'Calceranica al Lago', 'Maso Marini', 'MASO MARINI', '3', '5', '8', '3', '0', '0', '0', '5', '8', 'si', 'no', 'no', 'no', 'no', '0', '0', '0', '0', 'no', '0', '0', 'no', '', 'no', '27', '39', '15', '4']

3. Geocoding con webapi

3.1 MapQuest / OpenStreetMap Nominatim

Possiamo leggere i valori dal CSV, ma purtroppo notiamo che mancano le coordinate geografiche. Per ottenerle, possiamo usare i servizi di MapQuest, che ci offre gratutitamente un cosiddetto servizio di geocoding : Dati degli indirizzi, ci ritornerà le loro coordinate geografiche usando OpenStreetMap (detto OSM per gli amici) come riferimento.

Per capire cosa potremmo avere indietro, cerchiamo su OpenStreetMap un agritur, tipo il Montibeller di Roncegno:

✪ DOMANDA 3.1.1: Le due stringhe trovano risultati diversi. Come mai? Manca forse qualche dato ad OpenStreetMap?

Mostra risposta

3.2 Webapi JSON

Oggigiorno, tantissimi portali offrono la possibilità di leggere e scrivere informazioni programmaticamente tramite cosiddette ‘API REST’. API significa Application Programming Interface, ed è una serie di specifiche su come accedere programmaticamente ai dati di un sito. Di solito, le API disponibili vengono descritte nella sezione sviluppatori.

✪ DOMANDA 3.2.2: prova ad andare sul sito di dati.gov.it e cerca dove sono le API. Provane qualcuna dal browser cercando di capire cosa viene ritornato.

Mostra risposta

Webapi geografiche

Abbiamo visto una bella rappresentazione grafica del punto sulla mappa. Però ci piacerebbe ottenere quell’informazione in Python. Come fare? openstreetmap.org offre delle API che potremmo usare, ma teniamo presente che OpenStreetMap è un servizio gratuito gestito principalmente su base volontaristica con risorse limitate.

In alternativa, conviene rivolgersi a servizi offerti da aziende commerciali che possono sostenere un traffico più elevato. Di interessante c’è MapQuest, che oltre a mappe commerciali, offre anche lo stesso identico servizio di OpenStreetMap (può farlo perchè le condizioni di licenza di OSM, molto libere, lo permettono). L’unico vincolo è che per usare il servizio bisogna prima registrare una cosiddetta ‘Api key’ da passare al servizio ogni volta che lo usiamo. Questo consente a MapQuest di monitorare eventuali abusi del servizio (per più info, vedere le condizioni di licenza di MapQuest. Quando ci connettiamo a indirizzi che iniziano con open.mapquestapi, vuol dire che stiamo usando mappe di OpenStreetMap.

Specifichiamo un paio di parametri importanti delle nostre chiamate web:

[2]:
api_key = "Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG"  # Usate questa key SOLO per fare questi esercizi!
url_base = "http://open.mapquestapi.com/nominatim/v1/search"

Provate a fare copia e incolla nel vostro broswer dell’indirizzo seguente:

[3]:
print(url_base)
http://open.mapquestapi.com/nominatim/v1/search

MapQuest dovrebbe rispondervi così:

The AppKey submitted with this request is invalid.

Si è offeso perchè non gli abbiamo passato una api key.

IMPORTANTE: Per oggi, la api key ve la diamo noi, ma se usate il servizio per i vostri progetti, registratevene una!!!!**

Proviamo ad aggiungere la api key, mettendo il tutto nel browser dovremmo vedere dei bottoni (notate che il primo parametro è sempre preceduto da il punto di domanda ?) :

[4]:
url_with_key = url_base + "?key=" + api_key
print(url_with_key)
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG

Se siamo riusciti a vedere dei bottoni, vuol dire che abbiamo superato il primo ostacolo. Ma Python di bottoni non ci capisce un tubo! Dobbiamo fornire a pyhton un formato più ‘digeribile’:

[5]:
url_json = url_base + "?key=" + api_key + "&format=json"

Se proviamo nel browser questa nuova url, vedremo che è sparito tutto - al più vedrai due parentesi quadre vuote []. Un JSON vuoto non è per niente interessante, ma almeno sono spariti i bottoni:

[6]:
print(url_json)
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json

Siamo finalmente pronti per eseguire la nostra prima query via web api ! Nella nostra query, scriveremo in linguaggio naturale Montibeller,Roncegno:

[7]:

query = "Montibeller,Roncegno"

url_complete = url_json = url_base + "?key=" + api_key + "&format=json"  + "&q=" + query

print(url_complete)
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&q=Montibeller,Roncegno

Adesso dovremmo vedere un risultato tipo questo:

[{"place_id":"6560673","licence":"Data \u00a9 OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright","osm_type":"node","osm_id":"673194565","boundingbox":["46.0469105","46.0469105","11.4115734","11.4115734"],"lat":"46.0469105","lon":"11.4115734","display_name":"Montibeller, Via Prose, Alps, Salembis, Roncegno Terme, Comunit\u00e0 Valsugana e Tesino, Provincia autonoma di Trento, Trentino-Alto Adige - S\u00fcdtirol, 38051, Italy","class":"tourism","type":"hotel","importance":0.211,"icon":"http:\/\/ip-10-98-183-183.mq-us-east-1.ec2.aolcloud.net:8000\/nominatim\/v1\/images\/mapicons\/accommodation_hotel2.p.20.png"}]

prova a copia e incollare il risultato in un editor che supporta i JSON, salva il file come .json e prova a dire all’editor di riformattare il documento. Se tutto va bene, dovrebbe venire fuori un bell’albero ordinato così:

[
    {
        "place_id": "6560673",
        "licence": "Data \u00a9 OpenStreetMap contributors, ODbL 1.0. http:\/\/www.openstreetmap.org\/copyright",
        "osm_type": "node",
        "osm_id": "673194565",
        "boundingbox": [
            "46.0469105",
            "46.0469105",
            "11.4115734",
            "11.4115734"
        ],
        "lat": "46.0469105",
        "lon": "11.4115734",
        "display_name": "Montibeller, Via Prose, Alps, Salembis, Roncegno Terme, Comunit\u00e0 Valsugana e Tesino, TN, Trentino-Alto Adige - S\u00fcdtirol, 38051, Italy",
        "class": "tourism",
        "type": "hotel",
        "importance": 0.211,
        "icon": "http:\/\/ip-10-98-183-183.mq-us-east-1.ec2.aolcloud.net:8000\/nominatim\/v1\/images\/mapicons\/accommodation_hotel2.p.20.png"
    }
]

Mmm.. non sembra tanto diversa da una combinazione di liste e dizionari Python… Forse possiamo riuscire ad estrarre quel lat e lon senza neanche troppa fatica …

3.3. Requests in Python

Per chiamare le webapi da Python, installiamo la libreria requests:

  • Anaconda: conda install requests

  • Linux/Mac : python3 -m pip install --user requests

[8]:
# importiamo il modulo per la libreria:
import requests

query = "Montibeller,Roncegno"

url_complete = url_json = url_base + "?key=" + api_key + "&format=json"  + "&q=" + query


# effettuiamo una chiamata HTTP GET:

r = requests.get(url_complete)

Stampando direttamente r, vedremo qual’è stato il codice di risposta. Se è 200, vuol dire che è andato tutto bene. er altri possibili codici di risposta, puoi guardare Wikipedia

[9]:
print(r)
<Response [200]>

Possiamo accedere al contenuto testuale della risposta con r.text:

[10]:
r.text
[10]:
'[{"place_id":"6471026","licence":"Data © OpenStreetMap contributors, ODbL 1.0. https:\\/\\/www.openstreetmap.org\\/copyright","osm_type":"node","osm_id":"673194565","boundingbox":["46.0468605","46.0469605","11.4115234","11.4116234"],"lat":"46.0469105","lon":"11.4115734","display_name":"Montibeller, Via Prose, Maso Vazzena, Larganza, Roncegno Terme, Comunità Valsugana e Tesino, TN, TAA, 38051, Italia","class":"tourism","type":"hotel","importance":0.211,"icon":"http:\\/\\/ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net\\/nominatim\\/images\\/mapicons\\/accommodation_hotel2.p.20.png"}]'
[11]:
type(r.text)
[11]:
str

Gli headers content-type ci dicono il tipo di formato e l’encoding dichiarato dal server (NOTA: purtroppo l’encoding dichiarato dal server non sempre corrisponde a quello effettivo !):

[12]:
r.headers['content-type']
[12]:
'application/json; charset=UTF-8'

Possiamo anche ottenere l’encoding direttamente:

[13]:
r.encoding
[13]:
'UTF-8'

Dalle ispezioni fatte sinora, abbiamo capito che abbiamo ottenuto una stringa in formato json. requests mette a disposizione un comodo metodo che interpreta la stringa come json, e ritorna delle strutture dati Python per accedere facilmente ai campi interni del json. Quali strutture? Come avrete notato, il formato del json è molto simile a strutture dati che già abbiamo in python, come stringhe, numeri interi, float, liste e dizionari. L’unica differenza sono i campi null in json che diventano None in Python. Quindi la conversione a Python è quasi sempre facile e indolore:

[14]:
r.json()
[14]:
[{'place_id': '6471026',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '673194565',
  'boundingbox': ['46.0468605', '46.0469605', '11.4115234', '11.4116234'],
  'lat': '46.0469105',
  'lon': '11.4115734',
  'display_name': 'Montibeller, Via Prose, Maso Vazzena, Larganza, Roncegno Terme, Comunità Valsugana e Tesino, TN, TAA, 38051, Italia',
  'class': 'tourism',
  'type': 'hotel',
  'importance': 0.211,
  'icon': 'http://ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/accommodation_hotel2.p.20.png'}]

Notiamo che abbiamo ricevuto una lista di dizionari:

[15]:
type(r.json())
[15]:
list

Prendiamo il primo dizionario:

[16]:
r.json()[0]
[16]:
{'place_id': '6471026',
 'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
 'osm_type': 'node',
 'osm_id': '673194565',
 'boundingbox': ['46.0468605', '46.0469605', '11.4115234', '11.4116234'],
 'lat': '46.0469105',
 'lon': '11.4115734',
 'display_name': 'Montibeller, Via Prose, Maso Vazzena, Larganza, Roncegno Terme, Comunità Valsugana e Tesino, TN, TAA, 38051, Italia',
 'class': 'tourism',
 'type': 'hotel',
 'importance': 0.211,
 'icon': 'http://ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/accommodation_hotel2.p.20.png'}
[17]:
type(r.json()[0])
[17]:
dict

Prendiamo il campo lat dal primo dizionario:

[18]:
r.json()[0]['lat']
[18]:
'46.0469105'
[19]:
r.json()[0]['lon']
[19]:
'11.4115734'

✪ DOMANDA 3.3.1: Come è stato convertito in Python il campo lat. Numero o qualcos’altro? In cosa potremmo convertirlo?:

Mostra soluzione
[20]:
# scrivi qui


<class 'str'>
11.4115734

✪ ESERCIZIO 3.3.2: prova a chiamare requests.get passandogli una URL sbagliata, come boh o parzialmente giusta come http://open.mapquestapi.com/BLA. Cosa ottieni di ritorno per i vari campi di r? Il codice HTTP di ritorno (successo / errore) ti sembra consistente con il risultato che ottieni?

Mostra soluzione
[21]:
# scrivi qui


[21]:
<Response [200]>

Notiamo che pur richiedendo una pagina inesistente, il sito di mapquest (a Marzo 2018) ci ritorna un codice http 200 che indicherebbe ‘successo’. Questo comportamento può essere molto pericoloso, perchè può indurre programmi che ricevono la pagina a ritenere di aver ottenuto effettivamente quello che chiedevano, quando invece si dovrebbe essere verificato un errore. A peggiorare le cose, se avete TIM a volte ci si mettono di mezzo pure loro: a Ottobre 2016, se voi richiedete un indirizzo inesistente (http://bla), la TIM vi rimanda ad una pagina di cortesia che dice Spiacenti, l'indirizzo digitato nonesiste, ma mandava indietro al browser un codice di successo dal valore 200 !

3.4 Funzioni geocode per requests

Proviamo a scriverci delle funzioni comode per effettuare delle chiamate semplicemente passando un indirizzo

[22]:
def geocode_generic(address):
    # 'payload' è una variabile che ci definiamo noi, per metterci più comodamente i parametri
    # dentro un dizionario
    payload = {'key': api_key,  # Questa è la chiave lunga tipo Er38Wk... che abbiamo definito più sopra
               'format': 'json',
               'q' : address}
    r = requests.get(url_base, params=payload)  # qua passiamo il dizionario 'payload' alla libreria requests
    print(r.url) # stampa l'url che requests ha usato
    return r.json()

Facciamo una prova:

[23]:
geocode_generic("Montibeller, Roncegno")
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&q=Montibeller%2C+Roncegno
[23]:
[{'place_id': '6471026',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '673194565',
  'boundingbox': ['46.0468605', '46.0469605', '11.4115234', '11.4116234'],
  'lat': '46.0469105',
  'lon': '11.4115734',
  'display_name': 'Montibeller, Via Prose, Maso Vazzena, Larganza, Roncegno Terme, Comunità Valsugana e Tesino, TN, TAA, 38051, Italia',
  'class': 'tourism',
  'type': 'hotel',
  'importance': 0.211,
  'icon': 'http://ip-10-98-178-30.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/accommodation_hotel2.p.20.png'}]

A volte essere precisi non aiuta:

[24]:
json = geocode_generic("Montibeller, Via Prose n. 1, Roncegno")
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&q=Montibeller%2C+Via+Prose+n.+1%2C+Roncegno
[25]:
print(json)
[]

Per verificare se abbiamo trovato o meno qualcosa, possiamo controllare che la lunghezza della lista ritornata sia zero con len:

[26]:
if len(json) == 0:
    print("non ho trovato niente!")
else:
    print("ho trovato !")
non ho trovato niente!
[27]:
geocode_generic("Via Prose n. 1, Roncegno")
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&q=Via+Prose+n.+1%2C+Roncegno
[27]:
[{'place_id': '106260827',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '149123476',
  'boundingbox': ['46.0464048', '46.047558', '11.4100616', '11.4119591'],
  'lat': '46.0469731',
  'lon': '11.4109589',
  'display_name': 'Via Prose, Maso Vazzena, Larganza, Roncegno Terme, Comunità Valsugana e Tesino, TN, TAA, 38051, Italia',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.525}]

Con query generiche è possibile che vengano ritornati parecchi risultati:

✪ DOMANDA 3.4.1: Qual’è il risultato più rilevante secondo Nominatim (ricordiamo che Nominatim è il search engine di OpenStreetMap)? E quanto è rilevante ? Qual’è la rilevanza minimima? Qual’è la massima ?

Mostra risposta
[28]:
geocode_generic("Trento")
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&q=Trento
[28]:
[{'place_id': '186698302',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'relation',
  'osm_id': '46663',
  'boundingbox': ['45.9775306', '46.1530112', '11.0224735', '11.1948226'],
  'lat': '46.0664228',
  'lon': '11.1257601',
  'display_name': "Trento, Territorio Val d'Adige, TN, TAA, Italia",
  'class': 'place',
  'type': 'city',
  'importance': 0.26364591679333,
  'icon': 'http://ip-10-98-173-122.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_place_city.p.20.png'},
 {'place_id': '187948156',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'relation',
  'osm_id': '3870471',
  'boundingbox': ['7.9378151', '8.292381', '126.00048', '126.355208'],
  'lat': '8.114415',
  'lon': '126.158888603496',
  'display_name': 'Trento, Agusan del Sur, Caraga, 8505, Philippines',
  'class': 'boundary',
  'type': 'administrative',
  'importance': 0.2225,
  'icon': 'http://ip-10-98-173-122.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_boundary_administrative.p.20.png'},
 {'place_id': '652743',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '248804218',
  'boundingbox': ['46.0721752', '46.0722752', '11.1189539', '11.1190539'],
  'lat': '46.0722252',
  'lon': '11.1190039',
  'display_name': "Trento, Piazzetta Filippo Foti e Edoardo Martini, Centro storico Trento, Trento, Territorio Val d'Adige, TN, TAA, 38122, Italia",
  'class': 'railway',
  'type': 'stop',
  'importance': 0.18947959270135},
 {'place_id': '43377314',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '3134911289',
  'boundingbox': ['44.9456976', '44.9856976', '11.4473224', '11.4873224'],
  'lat': '44.9656976',
  'lon': '11.4673224',
  'display_name': 'Trento, RO, VEN, Italia',
  'class': 'place',
  'type': 'hamlet',
  'importance': 0.17875,
  'icon': 'http://ip-10-98-173-122.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_place_village.p.20.png'},
 {'place_id': '531699',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '198505670',
  'boundingbox': ['8.0059463', '8.0859463', '126.0214264', '126.1014264'],
  'lat': '8.0459463',
  'lon': '126.0614264',
  'display_name': 'Trento, Agusan del Sur, Caraga, 8505, Philippines',
  'class': 'place',
  'type': 'town',
  'importance': 0.16650761976897,
  'icon': 'http://ip-10-98-173-122.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_place_town.p.20.png'},
 {'place_id': '105325154',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '147148070',
  'boundingbox': ['44.1482269', '44.1507838', '4.8476098', '4.850579'],
  'lat': '44.14948815',
  'lon': '4.84974947145189',
  'display_name': "Trento, La Baussenque, Orange, Carpentras, Vaucluse, Provence-Alpes-Côte d'Azur, France métropolitaine, 84100, France",
  'class': 'landuse',
  'type': 'industrial',
  'importance': 0.16},
 {'place_id': '166654422',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '431617802',
  'boundingbox': ['46.0782422', '46.0784452', '11.1421592', '11.1427322'],
  'lat': '46.0783806',
  'lon': '11.1424334',
  'display_name': "Trento, Marnighe, Trento, Territorio Val d'Adige, TN, TAA, 38122, Italia",
  'class': 'highway',
  'type': 'pedestrian',
  'importance': 0.135},
 {'place_id': '132505515',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '252075211',
  'boundingbox': ['-32.9847715', '-32.9825163', '-60.6614742', '-60.6609117'],
  'lat': '-32.9836455',
  'lon': '-60.6611934',
  'display_name': 'Trento, Villa Moreno, Domingo Matheu, Distrito Sur, Rosario, Municipio de Rosario, Departamento Rosario, Sta. Fe, S2000, Argentina',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.135},
 {'place_id': '89398989',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '73838593',
  'boundingbox': ['-32.9893919', '-32.985958', '-60.6626152', '-60.6617997'],
  'lat': '-32.9882128',
  'lon': '-60.6623171',
  'display_name': 'Trento, La Guardia, Distrito Sur, Rosario, Municipio de Rosario, Departamento Rosario, Sta. Fe, S2000, Argentina',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.135},
 {'place_id': '89720595',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '80595940',
  'boundingbox': ['45.7466148', '45.7469574', '9.2305622', '9.2319169'],
  'lat': '45.7468391',
  'lon': '9.2310522',
  'display_name': 'Trento, Inverigo, CO, LOM, 22044, Italia',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.135}]

✪✪✪ ESERCIZIO 3.4.2: guardando anche la documentazione di sorted scrivere del codice python per riordinare i risultati precedenti dal meno rilevante al più rilevante. Ci sono vari modi per farlo, ma il più sintetico è con funzioni lambda. Riuscite a usarlo?

SUGGERIMENTO: Per ottenere per es. il campo 'osm_id' di un dizionario miodiz, si può chiamare il metodo miodiz.get('odm_id')

Mostra soluzione
[29]:
# scrivi qui


http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&q=Trento
[29]:
[{'place_id': '166654422',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '431617802',
  'boundingbox': ['46.0782422', '46.0784452', '11.1421592', '11.1427322'],
  'lat': '46.0783806',
  'lon': '11.1424334',
  'display_name': "Trento, Marnighe, Trento, Territorio Val d'Adige, TN, TAA, 38122, Italia",
  'class': 'highway',
  'type': 'pedestrian',
  'importance': 0.135},
 {'place_id': '132505515',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '252075211',
  'boundingbox': ['-32.9847715', '-32.9825163', '-60.6614742', '-60.6609117'],
  'lat': '-32.9836455',
  'lon': '-60.6611934',
  'display_name': 'Trento, Villa Moreno, Domingo Matheu, Distrito Sur, Rosario, Municipio de Rosario, Departamento Rosario, Sta. Fe, S2000, Argentina',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.135},
 {'place_id': '89398989',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '73838593',
  'boundingbox': ['-32.9893919', '-32.985958', '-60.6626152', '-60.6617997'],
  'lat': '-32.9882128',
  'lon': '-60.6623171',
  'display_name': 'Trento, La Guardia, Distrito Sur, Rosario, Municipio de Rosario, Departamento Rosario, Sta. Fe, S2000, Argentina',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.135},
 {'place_id': '89720595',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '80595940',
  'boundingbox': ['45.7466148', '45.7469574', '9.2305622', '9.2319169'],
  'lat': '45.7468391',
  'lon': '9.2310522',
  'display_name': 'Trento, Inverigo, CO, LOM, 22044, Italia',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.135},
 {'place_id': '105325154',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '147148070',
  'boundingbox': ['44.1482269', '44.1507838', '4.8476098', '4.850579'],
  'lat': '44.14948815',
  'lon': '4.84974947145189',
  'display_name': "Trento, La Baussenque, Orange, Carpentras, Vaucluse, Provence-Alpes-Côte d'Azur, France métropolitaine, 84100, France",
  'class': 'landuse',
  'type': 'industrial',
  'importance': 0.16},
 {'place_id': '531699',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '198505670',
  'boundingbox': ['8.0059463', '8.0859463', '126.0214264', '126.1014264'],
  'lat': '8.0459463',
  'lon': '126.0614264',
  'display_name': 'Trento, Agusan del Sur, Caraga, 8505, Philippines',
  'class': 'place',
  'type': 'town',
  'importance': 0.16650761976897,
  'icon': 'http://ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_place_town.p.20.png'},
 {'place_id': '43377314',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '3134911289',
  'boundingbox': ['44.9456976', '44.9856976', '11.4473224', '11.4873224'],
  'lat': '44.9656976',
  'lon': '11.4673224',
  'display_name': 'Trento, RO, VEN, Italia',
  'class': 'place',
  'type': 'hamlet',
  'importance': 0.17875,
  'icon': 'http://ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_place_village.p.20.png'},
 {'place_id': '652743',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'node',
  'osm_id': '248804218',
  'boundingbox': ['46.0721752', '46.0722752', '11.1189539', '11.1190539'],
  'lat': '46.0722252',
  'lon': '11.1190039',
  'display_name': "Trento, Piazzetta Filippo Foti e Edoardo Martini, Centro storico Trento, Trento, Territorio Val d'Adige, TN, TAA, 38122, Italia",
  'class': 'railway',
  'type': 'stop',
  'importance': 0.18947959270135},
 {'place_id': '187948156',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'relation',
  'osm_id': '3870471',
  'boundingbox': ['7.9378151', '8.292381', '126.00048', '126.355208'],
  'lat': '8.114415',
  'lon': '126.158888603496',
  'display_name': 'Trento, Agusan del Sur, Caraga, 8505, Philippines',
  'class': 'boundary',
  'type': 'administrative',
  'importance': 0.2225,
  'icon': 'http://ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_boundary_administrative.p.20.png'},
 {'place_id': '186698302',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'relation',
  'osm_id': '46663',
  'boundingbox': ['45.9775306', '46.1530112', '11.0224735', '11.1948226'],
  'lat': '46.0664228',
  'lon': '11.1257601',
  'display_name': "Trento, Territorio Val d'Adige, TN, TAA, Italia",
  'class': 'place',
  'type': 'city',
  'importance': 0.26364591679333,
  'icon': 'http://ip-10-98-165-99.mq-us-east-1.ec2.aolcloud.net/nominatim/images/mapicons/poi_place_city.p.20.png'}]

La API di Nominatim (ricordiamo che Nominatim è il search engine di OpenStreetMap) ci permette di essere più specifici nei parametri che passiamo. Per esempio, si possono passare i parameteri street e county:

[30]:

def geocode_street_county(street, county):
    # 'payload' è una variabile che ci definiamo noi, per metterci più comodamente i parametri
    payload = {'key': api_key,  # api_key è la chiave lunga tipo Er38Wk... che abbiamo definito più sopra
               'format': 'json',
               'street' : street,
               'county' : county}
    r = requests.get(url_base, params=payload)  # qua passiamo il 'payload' alla libreria requests
    print(r.url) # stampa l'url che requests ha usato
    return r.json()


[31]:
geocode_street_county("Via Prose n. 1", "Roncegno")
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Via+Prose+n.+1&county=Roncegno
[31]:
[{'place_id': '106260827',
  'licence': 'Data © OpenStreetMap contributors, ODbL 1.0. https://www.openstreetmap.org/copyright',
  'osm_type': 'way',
  'osm_id': '149123476',
  'boundingbox': ['46.0464048', '46.047558', '11.4100616', '11.4119591'],
  'lat': '46.0469731',
  'lon': '11.4109589',
  'display_name': 'Via Prose, Maso Vazzena, Larganza, Roncegno Terme, Comunità Valsugana e Tesino, TN, TAA, 38051, Italia',
  'class': 'highway',
  'type': 'residential',
  'importance': 0.525}]

4. Scriviamo un nuovo CSV con i campi lat e long

Adesso che abbiamo capito come prenderci le coordinate, possiamo

  1. aprire in scrittura un nuovo CSV chiamato agritur_mini_latlon.csv

  2. leggere il CSV originale agritur_mini.csv

  3. per ogni riga del CSV originale agritur_mini.csv, leggere lat e lon da MapQuest

  4. scrivere nel nuovo CSV agritur_mini_latlon.csv i campi vecchi più le nuove coordinate

Attenzione: Per non sovraccaricare MapQuest, negli esercizi seguenti useremo SOLO il file agritur_mini.csv che contiene i primi 7 Agritur. Per un paio di questi sarà possibile trovare una georeferenziazione. Il CSV ‘soluzione’ lo potete vedere nel file agritur_soluzione.csv (NON modificatelo !)

Intanto scriviamo un programmino per leggere dall’input agritur_mini.csv e copiare tutto quanto letto in un file di output che chiameremo agritur_mini_latlon.csv

[32]:

import csv

# apriamo il file `agritur_mini_latlon`in scrittura (fouput è un nome  scelto da noi)
with open('agritur_mini_latlon.csv', 'w', encoding='utf-8') as foutput:
    scrittore = csv.writer(foutput)  # Ci serve creare un'oggetto 'scrittore'

    # apriamo il file `agritur_mini`in scrittura (finput è un nome  scelto da noi)
    with open('agritur_mini.csv', encoding='utf-8', newline='') as finput:
        lettore = csv.reader(finput, delimiter=';')  # delimitatore ';'
        for riga in lettore:
            scrittore.writerow(riga)  # chiamiamo l'oggetto scrittore dicendogli di scrivere la riga appena letta

✪ ESERCIZIO 4.1: Copia a mano qua sotto il codice qua sopra, e usa Control+Invio per eseguirlo

[33]:
# scrivi il codice

✪ ESERCIZIO 4.2: prova a cancellare il file agritur_mini_latlon.csv, eseguire la cella qua sopra e verificare che il programma effettivamente crei il file

✪ DOMANDA 4.3: di default, lo scrittore che separatori usa? Guarda il file di risultato.

SOLUZIONE: Usa la virgola

✪✪ ESERCIZIO 4.4: Prova ad aggiungere un contatore per verificare a che riga siamo, poi tanto per capire dove sta la latitudine, prova a modificare row prima che venga scritta, in modo che il campo Latitudine (row[16]) e Longitudine (row[17]) siano messi rispettivamente a 123 e 456

Mostra soluzione
[34]:
# scrivi qui


✪✪ ESERCIZIO 4.5: Mentre leggi il CSV, adesso setta latitudine e longitudine usando risultati ottenuti chiamando geocode_street_county definita precedentemente. Per gli input, puoi usare questi indici:

  • Indirizzo_agriturismo : riga[19]

  • Comune_Sede_Agriturismo : riga[18]

(ci sarebbe la Denominazione_Agriturismo : riga[20] ma come visto prima funziona solo se l’agriturismo è già in OpenStreetMap, usando solo la via abbiamo qualche probabilità in più di successo)

Mostra soluzione
[35]:

import requests

def geocode_street_county(street, county):
    # 'payload' è una variabile che ci definiamo noi, per metterci più comodamente i parametri
    payload = {'key': api_key,  # api_key è la chiave lunga tipo Er38Wk... che abbiamo definito più sopra
               'format': 'json',
               'street' : street,
               'county' : county}
    r = requests.get(url_base, params=payload)  # qua passiamo il 'payload' alla libreria requests
    print(r.url) # stampa l'url che requests ha usato
    return r.json()

# scrivi qui


http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Loc.+al+Lago+n.+15&county=Garniga+Terme
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Loc.+Pineta+-+Maso+Nello&county=Faedo
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Via+Casalini+n.+74&county=Sanzeno
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Via+Prose+n.+1&county=Roncegno
trovato !
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Loc.+Fontanelle&county=Tenno
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Via+Chimelli+n.+25&county=Pergine+Valsugana
trovato !
http://open.mapquestapi.com/nominatim/v1/search?key=Er38WkJVmeOl5AvFIAzM6lBBq4uEdgvG&format=json&street=Via+G.+Inama+n.+21&county=Coredo
trovato !

5. Importiamo in UMap

✪ ESERCIZIO 5.1 Importa il CSV in Umap, seguendo le indicazioni di del tutorial sui Servizi di Rovereto visto precedentemente al punto 0.2

Il risultato finale dovrebbe essere così: Mappa Agritur mini . Nota che abbiamo scritto %%HTML che è un comando speciale di Jupyter e poi incollato sotto il codice HTML ricavato da Umap:

[36]:
%%HTML

<iframe width="100%" height="300px" frameBorder="0" src="https://umap.openstreetmap.fr/en/map/mia-mappa-agritur_182055?scaleControl=false&miniMap=false&scrollWheelZoom=false&zoomControl=true&allowEdit=false&moreControl=true&searchControl=null&tilelayersControl=null&embedControl=null&datalayersControl=true&onLoadPanel=undefined&captionBar=false#11/46.0966/11.4024"></iframe><p><a href="http://umap.openstreetmap.fr/en/map/mia-mappa-agritur_182055">See full screen</a></p>

✪ ESERCIZIO 5.2: Crea una nuova cella qua sotto, e prova ad incorporare nel foglio Jupyter la tua mappa come fatto qua sopra:

[ ]: