import sys sys.path.append('..') import requests from time import sleep from db_layer.capturas_interface import capturas_interface from core.config import google_api_key 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': google_api_key} 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()