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, geocoder_delay from core import my_logger import logging class Geocoder: def __init__(self): self.cache = GeocodingCache() def start(self): logging.info("Starting geocoder.") while True: sleep(geocoder_delay) 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[b"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[b"fecha_captura"], geo_data["latitude"], geo_data["longitude"], geo_data["precision"], ) continue task = GeocodingTask(address) task.geocode() while not task.is_successfull(): logging.warning("Unsuccessful request.") 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[b"fecha_captura"], geo_data["latitude"], geo_data["longitude"], geo_data["precision"], ) break if not (task.tries > 3 or task.success_surrender_retry == "Surrender"): 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[b"fecha_captura"], geo_data["latitude"], geo_data["longitude"], geo_data["precision"], ) class GeocodingCache: cache_max_size = 2000 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() logging.info("Geocoder cache has reached max size. Making some room...") 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()