Prima di entrare nel merito delle tecniche di calcolo della domificazione, dobbiamo risolvere un problema: come trovo, in modo programmatico, le coordinate di un luogo geografico? Posso usare un datebase di località, naturalmente, vi ho già mostrato come ricavare una semplice tabella con milioni di località e trasformarla in un database sqlite, qualche post addietro, abbiamo anche costruito un widget apposito. Il problema è che i database sono, in genere, molto pesanti da portarsi dietro, si arriva facilmente a qualche decina di mega e non è detto che siamo sempre in condizioni di installarli nel memoria di un dispositivo, se abbiamo qualche limitazione di risorse.
Considerato che il web è un enorme deposito di informazioni, comprese quelle di natura geografica, possiamo pensare, volendo, a utilizzare un servizio REST come quello che mette a disposizione Google: Google Maps Geocoding API, che è gratuito per usi limitati e richiede l'apertura di un account, una API key, e il pagamento oltre una certa soglia di utilizzo, oppure quello di geonames.org che è il sito che mette a disposizione quell'enorme database che ho usato per costruire il mio widget e sicuramente molti altri.
Oggi voglio invece provare a usare un metodo più ruvido e gratuito, basato su wikipedia e su alcune librerie python. Ve ne parlo succintamente, un trafiletto per ogni libreria.
Wikipedia
Per ogni luogo nel mondo, per quanto piccolo, Wikipedia fornisce una pagina in cui sono riportate le coordinate geografiche del luogo. Spulciando nel sorgente della pagina, non è difficile individuarle ed estrarle usando le tecniche delle espressioni regolari, presenti nella Python Standard Library. Preferisco, fra tutte, l'edizione inglese, cosa di cui dobbiamo tener conto quando cerchiamo un nome di città. In quel grande contenitore di librerie python che è Pypi ho trovato un'API per wikipedia pronta per l'uso, che dovremo quindi installare preliminarmente :
# Se non l'avete già fatto: sudo pip install python-pip <Invio> # quindi usate pip per installare wikipedia pip install wikipedia <Invio>
Per la necessità o meno di usare i diritti di amministratore o per Windows o Mac vi prego di controllare la documentazione relativa all'uso di pip. La libreria python wikipedia è soggetta a licenza MIT.
Requests: HTTP for Humans
Se avete mai usato urllib e urlib2 apprezzerete questo piccolo gioiello di Kenneth Reitz, che consente di accedere al contenuto di una pagina web, anche in forma di xml o json dove previsto, in un soffio.
Per installare questa libreria si procede come prima:
pip install requests
La licenza d'uso è Apache 2.0
timezonefinder
Se Wikipedia ci aiuta moltissimo a trovare le coordinate geografiche, usa una rappresentazione della timezone del luogo basata sullo scarto orario da UTC, che diventa complicata da gestire. Con questa libreria posso facilmente ottenere, in base alle coordinate geografiche, la timezone del luogo espressa come "Europe/Rome" e simili, lasciando ad altre librerie il compito di gestire l'ora estiva
Installazione:
pip install timezonefinder
La libreria è di J. Michelfeit, ed è pubblicata su Pypi con licenza MIT
MyLittleTownFinder
Veniamo dunque al codice con cui gestire tutte le complesse operazioni di ricerca ed estrazione delle coordinate geografiche.
Wikipedia è abbastanza regolare nel catalogare i nomi di città, per cui di fronte a toponimi unici, di solito basta comporre l'url così: https://en.wikipedia.org/wiki/nomedelposto e siamo nella pagina giusta. Non sempre è così semplice, per esempio se un nome di città è riportato più volte, per esempio Paris è la capitale della Francia, ma anche una ridente località del Texas (che ha dato il titolo ad un bellissimo film di Wim Wenders).
In questo e simili casi, dobbiamo escogitare un trucco per individuare la pagina di interesse tra le molte possibili. La prima funzione che vi presento, debitamente commentata, fa proprio questo.
import sys import re import requests import wikipedia as wk from timezonefinder import TimezoneFinder as tfz def find_a_place_wikipage(): # first input the name of a place, in English, if possible town = raw_input("city, town, or village: ") # the wikipedia search function gets a list of all the available pages urls = wk.search(town) # the list is printed to the screen, one element at a time, # each element preceded by its ordinal numbers. The user can choose an # element or type 99 to exit for x,y in enumerate(urls): print x,y print "99 to quit" n = 9999 while n not in range(len(urls)): n = int (raw_input("select a link : ")) if (n==99): sys.exit() # the choosen page is returned to the caller return urls[n]
Questa funzione cerca di inviduare la pagina corrispondente alla città che cerchiamo. Nel caso non trovi una voce che ci sembra quella corretta, perchè per esempio cerchiamo Venice ma non quella italiana, magari quella in Florida o in Illinois, possiamo aggiungere queste specificazioni geografiche alla stringa di ricerca, il motore di ricerca punterà con maggiore facilità alla voce giusta.
La seconda funzione è quella che gestisce il recupero dei dati dalla pagina che abbiamo individuato. E' abbastanza semplice e commentata, per cui ve la lascio esaminare senza ulteriori discussioni.
def get_coordinates(location): # location is given by the caller base_url = 'https://en.wikipedia.org/wiki/' # a complete url is formed url = base_url + location # a page request is sent, if HTTP request is successful # then the procedure goes on, else is stopped page = requests.get(url) if page.status_code == requests.codes.ok: # the html text is retrieved b = page.text pattern = '(wgCoordinates":{"lat":)([+-]?\d*\.?\d*)(,"lon":)([+-]?\d*\.?\d*)' m = re.search(pattern, b) # a regular expression is compared to the text # if successful, the coordinates are extracted and converted to float if m: latitudine = float(m.group(2)) longitudine = float(m.group(4)) # timezonefinder is used to precisely locate the related timezone tf = tfz() timezone = tf.timezone_at(lat=latitudine, lng=longitudine) # all three results are returned back to the caller as a tuple return (latitudine, longitudine, timezone) else: # unsuccessful operation print"not found, sorry" return None else: # error in HTTP request print "requests error" return None
Per finire qualche riga di codice per eseguire in serie le due funzioni.
if __name__ == '__main__': location = find_a_place_wikipage() result = get_coordinates(location) if result: lat, lon, timezone = result print "latitude {0} longitude {1} timezone {2} ".format(lat, lon, timezone)
Bene, facciamo qualche prova.
Python 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118] on linux2 Type "copyright", "credits" or "license()" for more information. >>> ========= RESTART: /home/ubuntu/Scrivania/proveStroBlog/cityurls.py ========= città: Roma 0 Roma 1 Representation oligonucleotide microarray analysis 2 A.S. Roma 3 Roma (mythology) 4 Ruska Roma 5 Roma, Queensland 6 Servitka Roma 7 Atletico Roma F.C. 8 Colonia Roma 9 Town of Roma 99 to quit select a link : 0 not found, sorry >>> ========= RESTART: /home/ubuntu/Scrivania/proveStroBlog/cityurls.py ========= città: Rome 0 Rome 1 Rome, Georgia 2 Founding of Rome 3 History of Rome 4 Rome (TV series) 5 Rome Prize 6 Third Rome 7 Diocese of Rome 8 Sack of Rome 9 Province of Rome 99 to quit select a link : 0 latitude 41.9 longitude 12.5 timezone Europe/Rome >>>
Come potete vedere, ho inserito il nome di città nella dicitura italiana, ma sulla wikipedia in lingua inglese non trova niente. Una volta inserito il nome inglese, tutto fila liscio.
Un'altra prova:
Python 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118] on linux2 Type "copyright", "credits" or "license()" for more information. >>> ========= RESTART: /home/ubuntu/Scrivania/proveStroBlog/cityurls.py ========= città: moscow 0 Moscow 1 MoSCoW method 2 Moscow, Idaho 3 Moscow Metro 4 FC Moscow 5 Administrative divisions of Moscow 6 Moscow Conservatory 7 Mayor of Moscow 8 Grand Duchy of Moscow 9 Moscow Time 99 to quit select a link : 0 latitude 55.75 longitude 37.6166666667 timezone Europe/Moscow >>>
Notate che c'è una Moscow anche nell'Idaho, USA. Se selezionassi quel link avrei questo risultato:
Python 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118] on linux2 Type "copyright", "credits" or "license()" for more information. >>> ========= RESTART: /home/ubuntu/Scrivania/proveStroBlog/cityurls.py ========= città: moscow 0 Moscow 1 MoSCoW method 2 Moscow, Idaho 3 Moscow Metro 4 FC Moscow 5 Administrative divisions of Moscow 6 Moscow Conservatory 7 Mayor of Moscow 8 Moscow Time 9 Grand Duchy of Moscow 99 to quit select a link : 2 latitude 46.73 longitude -117.0 timezone America/Los_Angeles >>>
Facciamo direttamente la ricerca di Paris, Texas per vedere come se la cava.
Python 2.7.13 (default, Jan 19 2017, 14:48:08) [GCC 6.3.0 20170118] on linux2 Type "copyright", "credits" or "license()" for more information. >>> ========= RESTART: /home/ubuntu/Scrivania/proveStroBlog/cityurls.py ========= città: paris texas 0 Paris, Texas 1 Paris, Texas (film) 2 Paris, Texas (band) 3 Lamar County, Texas 4 Paris Independent School District 5 Paris, Texas (disambiguation) 6 The Paris News 7 Paris (disambiguation) 8 Eiffel Tower (Paris, Texas) 9 First Church of Christ, Scientist (Paris, Texas) 99 to quit select a link : 0 latitude 33.662508 longitude -95.547692 timezone America/Chicago >>>
Mi sembra che funzioni benino. A questo punto penso che abbiamo un po' di materiale per andare oltre e iniziare a parlare della domificazione. A fra un po'.
No comments:
Post a Comment