import requests import json import time import os # Please convert this list into a dictionary of country -> locality/city -> Circuit name -> layouts (some circuits have multiple layouts) # it should be available_circuits = { "Argentina": { "Buenos Aires": { "Autódromo Juan y Oscar Gálvez": {1953: "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1953-1960.geo.json", 1954: "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1953-1960.geo.json", ...} } } } available_circuits = [ "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1953-1960.geo.json", "France - Rouen - Circuit de Rouen-Les-Essarts - 1957-1968.geo.json", "Singapore - Singapore - Marina Bay Street Circuit - 2008-.geo.json", "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1971-1973.geo.json", "Germany - Berlin - AVUS - 1921-1959.geo.json", "South Africa - East London - Prince George Circuit - 1934-1967.geo.json", "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1974-1981.geo.json", "Germany - Hockenheim - Hockenheimring - 1932-.geo.json", "South Africa - Kyalami - Kyalami Grand Prix Circuit - 1961-1985.geo.json", "Argentina - Buenos Aires - Autódromo Juan y Oscar Gálvez - 1995-1998.geo.json", "Germany - Nürburg - Nürburgring - 1927-.geo.json", "South Africa - Kyalami - Kyalami Grand Prix Circuit - 1992-1993.geo.json", "Australia - Adelaide - Adelaide Street Circuit - 1985-1995.geo.json", "Great Britain - Aintree - Aintree Circuit - 1954-1962.geo.json", "Spain - Barcelona - Circuit de Barcelona-Catalunya - 1991-.geo.json", "Australia - Melbourne - Albert Park Circuit - 1953-.geo.json", "Great Britain - Brands Hatch - Brands Hatch Circuit - 1964-1974.geo.json", "Spain - Jarama - Circuito del Jarama - 1967-1981.geo.json", "Austria - Spielberg - A1 Ring - 1997-2003.geo.json", "Great Britain - Brands Hatch - Brands Hatch Circuit - 1976-1987.geo.json", "Spain - Jerez - Circuito de Jerez - 1985-1991.geo.json", "Austria - Spielberg - Österreichring - 1969-1976.geo.json", "Great Britain - Silverstone - Silverstone Circuit - 1948-.geo.json", "Spain - Jerez - Circuito de Jerez - 1994-.geo.json", "Austria - Spielberg - Österreichring - 1977-1987.geo.json", "Hungary - Budapest - Hungaroring - 1986-.geo.json", "Spain - Montjuïc - Montjuïc Circuit - 1969-1975.geo.json", "Austria - Spielberg - Red Bull Ring - 2014-.geo.json", "Italy - Imola - Autodromo Enzo e Dino Ferrari - 1953-.geo.json", "Spain - Pedralbes - Pedralbes Circuit - 1946-1954.geo.json", "Austria - Zeltweg - Österreichring - 1963-1968.geo.json", "Italy - Monza - Autodromo Nazionale Monza - 1922-.geo.json", "Spain - Valencia - Valencia Street Circuit - 2008-2012.geo.json", "Azerbaijan - Baku - Baku City Circuit - 2016-.geo.json", "Italy - Pescara - Pescara Circuit - 1924-1957.geo.json", "Sweden - Anderstorp - Scandinavian Raceway - 1968-1977.geo.json", "Bahrain - Sakhir - Bahrain International Circuit - 2002-.geo.json", "Italy - Scarperia e San Piero - Autodromo Internazionale del Mugello - 1914-.geo.json", "Sweden - Anderstorp - Scandinavian Raceway - 1978-1997.geo.json", "Bahrain - Sakhir - Bahrain International Circuit - 2010.geo.json", "Japan - Aida - TI Circuit Aida - 1990-1997.geo.json", "Switzerland - Bern - Circuit Bremgarten - 1934-1954.geo.json", "Belgium - Nivelles - Circuit Nivelles-Baulers - 1971-1974.geo.json", "Japan - Fuji - Fuji Speedway - 1976-1977.geo.json", "Turkey - Istanbul - Intercity Istanbul Park - 2005-.geo.json", "Belgium - Spa Francorchamps - Circuit de Spa-Francorchamps - 1950-1978.geo.json", "Japan - Fuji - Fuji Speedway - 2007-.geo.json", "United Arab Emirates - Yas Marina - Yas Marina Circuit - 2009-.geo.json", "Belgium - Spa Francorchamps - Circuit de Spa-Francorchamps - 1983-.geo.json", "Japan - Suzuka - Suzuka International Racing Course - 1962-.geo.json", "USA - Austin - Circuit of the Americas - 2012-.geo.json", "Belgium - Zolder - Circuit Zolder - 1963-.geo.json", "Malaysia - Sepang - Sepang International Circuit - 1999-.geo.json", "USA - Dallas - Fair Park - 1984.geo.json", "Brazil - Jacarepaguá - Autódromo Internacional Nelson Piquet - 1977-.geo.json", "Mexico - Magdalena Mixhuca - Autódromo Magdalena Mixhuca - 1959-1970.geo.json", "USA - Detroit - Detroit Street Circuit - 1982-1988.geo.json", "Brazil - Sao Paulo - Autódromo José Carlos Pace - Interlagos - 1940-.geo.json", "Mexico - Mexico City - Autódromo Hermanos Rodríguez - 1962-.geo.json", "USA - Indianapolis - Indianapolis Motor Speedway - 1909-.geo.json", "Canada - Montreal - Circuit Gilles-Villeneuve - 1978-.geo.json", "Monaco - Monaco - Circuit de Monaco - 1929-.geo.json", "USA - Las Vegas - Las Vegas Street Circuit - 2023-.geo.json", "Canada - Mont-Tremblant - Circuit Mont-Tremblant - 1964-1970.geo.json", "Morocco - Casablanca - Ain-Diab Circuit - 1957-1958.geo.json", "USA - Long Beach - Long Beach Grand Prix Circuit - 1976-1981.geo.json", "Canada - Mosport - Mosport Park - 1961-1977.geo.json", "Netherlands - Zandvoort - Circuit Zandvoort - 1948-1971.geo.json", "USA - Long Beach - Long Beach Grand Prix Circuit - 1982.geo.json", "China - Shanghai - Shanghai International Circuit - 2004-.geo.json", "Netherlands - Zandvoort - Circuit Zandvoort - 1972-1985.geo.json", "USA - Long Beach - Long Beach Grand Prix Circuit - 1983.geo.json", "France - Clermont-Ferrand - Circuit de Charade - 1958-1988.geo.json", "Netherlands - Zandvoort - Circuit Zandvoort - 2021-.geo.json", "USA - Miami - Miami International Autodrome - 2022-.geo.json", "France - Dijon-Prenois - Circuit de Dijon-Prenois - 1972-1984.geo.json", "Portugal - Estoril - Autódromo do Estoril - 1972-.geo.json", "USA - Phoenix - Phoenix Street Circuit - 1989-1990.geo.json", "France - Le Castellet - Circuit Paul Ricard - 1969-.geo.json", "Portugal - Monsanto - Monsanto Park Circuit - 1954-1959.geo.json", "USA - Phoenix - Phoenix Street Circuit - 1991.geo.json", "France - Le Mans - Circuit de la Sarthe - 1923-1966.geo.json", "Portugal - Oporto - Circuito da Boavista - 1958-1960.geo.json", "USA - Riverside - Riverside International Raceway - 1960.geo.json", "France - Magny-Cours - Circuit de Nevers Magny-Cours - 1960-.geo.json", "Portugal - Portimão - Autódromo Internacional do Algarve - 2008-.geo.json", "USA - Sebring - Sebring International Raceway - 1959.geo.json", "France - Reims - Circuit de Reims-Gueux - 1926-1951.geo.json", "Qatar - Lusail - Losail International Circuit - 2004-.geo.json", "USA - Watkins Glen - Watkins Glen International - 1948-1980.geo.json", "France - Reims - Circuit de Reims-Gueux - 1952-.geo.json", "Russia - Sochi - Sochi Autodrom - 2014-.geo.json", "France - Rouen - Circuit de Rouen-Les-Essarts - 1952.geo.json", "Saudi Arabia - Jeddah - Jeddah Corniche Circuit - 2021-.geo.json" ] def fetch_all_grand_prix_data(): """ Fetches all Formula 1 Grand Prix data from the Ergast API across multiple pages and returns the races. """ base_url = "https://ergast.com/api/f1.json" limit = 100 # Maximum number of results per page offset = 0 all_races = [] total_races = None print("Fetching Grand Prix data from Ergast API...") while True: # Construct URL with pagination parameters url = f"{base_url}?limit={limit}&offset={offset}" print(f"Fetching data from offset {offset}...") # Add a small delay to avoid hitting rate limits time.sleep(0.5) # Make the request response = requests.get(url) # Check if request was successful if response.status_code != 200: print(f"Error fetching data: HTTP {response.status_code}") print(response.text) break # Parse the JSON response data = response.json() # Get total number of races if not already set if total_races is None: total_races = int(data['MRData']['total']) print(f"Total races to fetch: {total_races}") # Extract the races from this page races = data['MRData']['RaceTable'].get('Races', []) all_races.extend(races) # Update the offset for the next page offset += limit # Check if we've fetched all data if offset >= total_races: break print(f"Successfully fetched {len(all_races)} races.") return all_races def get_circuit_file_mapping(): """ Creates a mapping of circuit information to corresponding circuit GeoJSON files. """ circuit_mapping = {} # Get circuit files from the circuits directory circuits_dir = "circuits" if os.path.exists(circuits_dir): circuit_files = [f for f in os.listdir(circuits_dir) if f.endswith('.geo.json')] for file_name in circuit_files: file_path = os.path.join(circuits_dir, file_name) try: with open(file_path, 'r', encoding='utf-8') as f: data = json.load(f) if 'features' in data and len(data['features']) > 0: feature = data['features'][0] if 'properties' in feature: props = feature['properties'] if 'id' in props and 'Name' in props and 'Location' in props and 'seasons' in props: circuit_id = props['id'] circuit_name = props['Name'] location = props['Location'] seasons = props['seasons'] # Create a key for each season this circuit was used for season in seasons: key = (circuit_name, location, season) circuit_mapping[key] = file_name except Exception as e: print(f"Error processing circuit file {file_name}: {e}") return circuit_mapping def create_grand_prix_data(races, circuit_mapping): """ Create a dictionary of grand prix organized by name and season. Format: { "Belgian Grand Prix": { "1953": { "circuit": "belgium-circuit.geo.json", "date": "1953-06-22" } } } """ grand_prix_data = {} for race in races: race_name = race.get('raceName', 'Unknown Grand Prix') season = race.get('season', 'Unknown') # Create the GP entry if it doesn't exist if race_name not in grand_prix_data: grand_prix_data[race_name] = {} # Extract circuit info circuit = race.get('Circuit', {}) circuit_name = circuit.get('circuitName', 'Unknown Circuit') location = circuit.get('Location', {}) locality = location.get('locality', 'Unknown') # Create season entry season_entry = { "date": race.get('date', ''), "circuit_name": circuit_name, "location": locality, "country": location.get('country', 'Unknown'), "round": race.get('round', '') } # Try to match with a circuit file circuit_key = (circuit_name, locality, int(season)) if circuit_key in circuit_mapping: season_entry["circuit"] = circuit_mapping[circuit_key] else: # Try to find a close match for (name, loc, year), file_name in circuit_mapping.items(): if name == circuit_name and loc == locality: season_entry["circuit"] = file_name break # Add to the grand prix data grand_prix_data[race_name][season] = season_entry return grand_prix_data def create_seasons_data(races): """ Create a dictionary of races organized by season and round. Format: { "1950": { "1": { "name": "British Grand Prix", "date": "1950-05-13", "circuit": {...} } } } """ seasons_data = {} for race in races: season = race.get('season', 'Unknown') round_num = race.get('round', 'Unknown') # Create the season entry if it doesn't exist if season not in seasons_data: seasons_data[season] = {} # Extract essential race information race_name = race.get('raceName', 'Unknown Grand Prix') circuit = race.get('Circuit', {}) location = circuit.get('Location', {}) # Create race entry race_entry = { "name": race_name, "date": race.get('date', ''), "time": race.get('time', ''), "url": race.get('url', ''), "circuit": { "name": circuit.get('circuitName', 'Unknown Circuit'), "url": circuit.get('url', ''), "location": { "lat": location.get('lat', ''), "long": location.get('long', ''), "locality": location.get('locality', ''), "country": location.get('country', '') } } } # Add race results and other data if available if 'Results' in race: race_entry['results'] = race['Results'] if 'Qualifying' in race: race_entry['qualifying'] = race['Qualifying'] if 'Sprint' in race: race_entry['sprint'] = race['Sprint'] # Add to the seasons data seasons_data[season][round_num] = race_entry return seasons_data def main(): # Fetch all race data all_races = fetch_all_grand_prix_data() # Get circuit file mapping circuit_mapping = get_circuit_file_mapping() print(f"Found {len(circuit_mapping)} circuit mappings") # Create grand prix data grand_prix_data = create_grand_prix_data(all_races, circuit_mapping) print(f"Created grand prix data with {len(grand_prix_data)} entries") # Create seasons data seasons_data = create_seasons_data(all_races) print(f"Created seasons data with {len(seasons_data)} seasons") # Save to files with open('grand_prix.json', 'w', encoding='utf-8') as f: json.dump(grand_prix_data, f, indent=2, ensure_ascii=False) print("Saved grand_prix.json") with open('seasons.json', 'w', encoding='utf-8') as f: json.dump(seasons_data, f, indent=2, ensure_ascii=False) print("Saved seasons.json") if __name__ == "__main__": main()