get_rider_victories
Retrieve a detailed list of a cyclist's UCI-registered race victories, including race categories, dates, and years. Optionally filter results to display only WorldTour wins. Use rider ID to fetch data.
Instructions
Get a comprehensive list of a rider's UCI victories. This tool retrieves detailed information about all UCI-registered race victories achieved by the cyclist throughout their career. Victories can be filtered to show only WorldTour wins if desired.
Note: If you don't know the rider's ID, use the search_rider tool first to find it by name.
Example usage:
- Get all UCI victories for Tadej Pogačar (ID: 16973)
- Get WorldTour victories for Jonas Vingegaard (ID: 16974)
Returns a formatted string with:
- Complete list of victories
- Race details including category
- Date and year of each victory
- Option to filter by WorldTour races only
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| rider_id | Yes | ||
| world_tour_only | No |
Implementation Reference
- examples/rider_victories.py:10-47 (handler)The handler function named get_rider_victories that implements the tool logic by fetching rider victories using the API and displaying summary statistics.def get_rider_victories(rider_id): """Get a rider's victories from FirstCycling""" rider = Rider(rider_id) # Get basic rider info print(f"Rider ID: {rider.ID}") # Get all victories victories = rider.victories() # Display information about victories if hasattr(victories, 'results_df') and not victories.results_df.empty: print(f"\nFound {len(victories.results_df)} career victories:") # Group by year to count victories per year victories_by_year = victories.results_df.groupby('Year').size() print("\nVictories by year:") for year, count in victories_by_year.items(): print(f"{year}: {count} wins") # Check for specific race categories if 'CAT' in victories.results_df.columns: categories = victories.results_df['CAT'].value_counts() print("\nVictories by category:") for category, count in categories.items(): print(f"{category}: {count}") # Display the first 10 victories print("\nMost recent 10 victories:") # Sort by date (newest first) and show the first 10 if 'Date_Formatted' in victories.results_df.columns: recent_victories = victories.results_df.sort_values('Date_Formatted', ascending=False).head(10) # Display in a readable format for _, row in recent_victories.iterrows(): print(f"{row['Date_Formatted']}: {row['Race']} ({row['CAT']})") else: print("No victories found for this rider.")
- Supporting method in Rider class to fetch the victories data by calling the RiderVictories endpoint.def victories(self, world_tour=None, uci=None): """ Get the rider's victories. Parameters ---------- world_tour : bool True if only World Tour wins wanted uci : bool True if only UCI wins wanted Returns ------- RiderVictories """ return self._get_endpoint(endpoint=RiderVictories, high=1, k=1, uci=1 if uci else None, wt=1 if world_tour else None)
- The core parsing class for rider victories endpoint that extracts and formats the victories table into a pandas DataFrame.class RiderVictories(RiderEndpoint): """ Rider's victories. Extends RiderEndpoint. Attributes ---------- results_df : pd.DataFrame Table of rider's victories. """ def _parse_soup(self): super()._parse_soup() self._get_victories() def _get_victories(self): # Find table with victories table = self.soup.find('table', {'class': "sortTabell tablesorter"}) if table: # Check if the table has "No data" content no_data_text = table.get_text().strip() if "No data" in no_data_text: # Table exists but has no data self.results_df = pd.DataFrame() return try: # Try to parse using the parse_table function self.results_df = parse_table(table) if self.results_df is None: self.results_df = pd.DataFrame() # Empty DataFrame if no victories found except Exception as e: # If there's an error in parsing, handle it by creating a basic DataFrame manually print(f"Warning: Error parsing victories table: {str(e)}") # Fallback: Try to create a DataFrame directly from the HTML try: import io from dateutil.parser import parse # Parse the basic table html = str(table) self.results_df = pd.read_html(io.StringIO(html), decimal=',')[0] # Check if the table contains "No data" if (self.results_df.shape[0] == 1 and "No data" in self.results_df.iloc[0, 0]): self.results_df = pd.DataFrame() return # Clean up column names # The typical format is: Year | Date | Race | Category if 'Date.1' in self.results_df.columns: self.results_df.rename(columns={ 'Date': 'Year', 'Date.1': 'Date', 'Unnamed: 2': 'Month_Day' # This can be blank or contain additional date info }, inplace=True) # Convert Year to string self.results_df['Year'] = self.results_df['Year'].astype(str) # Handle date formatting - combine Year and Date if available if 'Month_Day' in self.results_df.columns: # Clean Month_Day column (keep only non-NaN values) self.results_df = self.results_df.drop('Month_Day', axis=1) # If Date column has decimal format (e.g., 22.04), treat as MM.DD format def format_date(row): try: if pd.notnull(row['Date']): date_str = row['Date'] if isinstance(date_str, float): # Convert float (22.04) to string and handle decimal date_parts = str(date_str).split('.') if len(date_parts) == 2: day = date_parts[0].zfill(2) month = date_parts[1].zfill(2) return f"{row['Year']}-{month}-{day}" return f"{row['Year']}-01-01" # Default date if format not recognized return f"{row['Year']}-01-01" # Default date if no Date value except: return f"{row['Year']}-01-01" # Default for any errors # Create formatted date column self.results_df['Date_Formatted'] = self.results_df.apply(format_date, axis=1) except Exception as e: # If all else fails, just return an empty DataFrame print(f"Warning: Error creating DataFrame from table HTML: {str(e)}") self.results_df = pd.DataFrame() else: # No table found self.results_df = pd.DataFrame()