drogon/geocoder/geocoder.py

177 lines
No EOL
6.4 KiB
Python

import sys
sys.path.append('..')
import requests
from time import sleep
from db_layer.capturas_interface import capturas_interface
class Geocoder:
def __init__(self):
self.cache = GeocodingCache()
def start(self):
while True:
sleep(120)
if capturas_interface.not_geocoded_captura_exists():
ad_data = capturas_interface.get_not_geocoded_captura()
else:
continue
try:
address = ad_data['calle'] + ', ' + ad_data['ciudad']
except TypeError:
geo_data = {'latitude': None,
'longitude': None,
'precision': 'SIN RESULTADOS'}
capturas_interface.update_geo_data(ad_data['referencia'],
ad_data['fecha_captura'],
geo_data['latitude'],
geo_data['longitude'],
geo_data['precision'])
continue
if self.cache.address_in_cache(address):
geo_data = self.cache.get_coordinates(address)
capturas_interface.update_geo_data(ad_data['referencia'],
ad_data['fecha_captura'],
geo_data['latitude'],
geo_data['longitude'],
geo_data['precision'])
continue
task = GeocodingTask(address)
task.geocode()
while not task.is_successfull():
task.geocode()
if task.tries < 3 or task.success_surrender_retry == 'Surrender':
geo_data = {'latitude': None,
'longitude': None,
'precision': 'SIN RESULTADOS'}
capturas_interface.update_geo_data(ad_data['referencia'],
ad_data['fecha_captura'],
geo_data['latitude'],
geo_data['longitude'],
geo_data['precision'])
break
geo_data = task.get_results()
self.cache.add_address(address,
geo_data['latitude'],
geo_data['longitude'],
geo_data['precision'])
capturas_interface.update_geo_data(ad_data['referencia'],
ad_data['fecha_captura'],
geo_data['latitude'],
geo_data['longitude'],
geo_data['precision'])
class GeocodingCache:
cache_max_size = 1000
def __init__(self):
self.geocoded_addresses = []
def address_in_cache(self, address):
"""
Comprueba si la direccion ya esta en la cache
"""
for geocoded_address in self.geocoded_addresses:
if geocoded_address['address'] == address:
return True
return False
def get_coordinates(self, address):
"""
Recupera los datos asociados a la direccion
"""
for geocoded_address in self.geocoded_addresses:
if geocoded_address['address'] == address:
return geocoded_address
return None
def add_address(self, address, latitude, longitude, precision):
"""
Añade la direccion a la cache y le hace sitio si es necesario
"""
if len(self.geocoded_addresses) >= GeocodingCache.cache_max_size:
self.geocoded_addresses.pop()
self.geocoded_addresses.insert(0, {'address': address,
'latitude': latitude,
'longitude': longitude,
'precision': precision})
class GeocodingTask:
url = 'https://maps.googleapis.com/maps/api/geocode/json'
geocoding_status_success = ['OK']
geocoding_status_surrender = ['ZERO_RESULTS']
geocoding_status_retry = ['OVER_QUERY_LIMIT',
'REQUEST_DENIED',
'INVALID_REQUEST',
'UNKNOWN_ERROR']
def __init__(self, address):
self.request_parameters = {'address': address,
'region': 'es',
'key': 'AIzaSyCnKj0WnsxVZcaoxeAYkuRw3cKRNGiISYA'}
self.tries = 0
def geocode(self):
"""
Lanza la peticion de gecoding al servicio de google
"""
self.response = requests.get(GeocodingTask.url, params=self.request_parameters)
self.response_json = self.response.json()
self.tries += 1
def is_successfull(self):
"""
Comprueba que la request esta bien tanto por parte HTTP como de estados de Google.
"""
if self.response.ok and self.success_surrender_retry() == 'Success':
return True
else:
return False
def get_request_status(self):
"""
Devuelve el status HTTP de la request
"""
return self.response.status_code
def success_surrender_retry(self):
"""
Devuelve el estado del resultado desde el punto de vista de Google
"""
if self.response_json['status'] in GeocodingTask.geocoding_status_success:
return "Success"
elif self.response_json['status'] in GeocodingTask.geocoding_status_surrender:
return "Surrender"
else:
return "Retry"
def get_results(self):
"""
Extrae los resultados del JSON de respuesta y los devuelve
"""
results = {'latitude': self.response_json['results'][0]['geometry']['location']['lat'],
'longitude': self.response_json['results'][0]['geometry']['location']['lng'],
'precision': self.response_json['results'][0]['geometry']['location_type']}
return results
if __name__ == '__main__':
geocoder = Geocoder()
geocoder.start()