Files
ffa-calendar/scripts/get_club_results.py
Muyue 6de44556f4 Feature: Add club results extractor and course details scraper
- Add get_club_results.py: Extract all results for a club from results CSV
  - Fuzzy search for club names
  - List clubs functionality
  - Export results to CSV
- Add scrape_course_details.py: Scrape detailed info from course pages
  - Extract competition ID (frmcompetition)
  - Extract event details (distance, category, sex)
  - Extract course website link
  - Extract location and organizer info
- Update README.md with new scripts and usage examples
- Update version to v1.3.0
2026-01-03 11:03:35 +01:00

219 lines
7.4 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Script pour récupérer tous les résultats d'un club depuis le CSV des résultats
Filtre simple sur le nom du club dans results_daily.csv
"""
import sys
import os
import pandas as pd
import csv
import argparse
from datetime import datetime
def get_club_results(club_name, results_file="data/results_daily.csv", output_dir="data/exports", fuzzy_match=True):
"""
Récupérer tous les résultats d'un club
Args:
club_name: Nom du club à rechercher
results_file: Fichier CSV des résultats
output_dir: Répertoire de sortie pour l'export
fuzzy_match: Utiliser la recherche floue (contient) ou exacte
Returns:
DataFrame pandas avec les résultats du club
"""
print(f"Recherche du club: {club_name}")
print(f"Fichier source: {results_file}")
# Lire le fichier CSV
try:
# Lire par chunks si le fichier est très gros
df = pd.read_csv(results_file, encoding='utf-8-sig')
print(f"{len(df)} résultats chargés")
except Exception as e:
print(f"✗ Erreur lecture CSV: {e}")
return None
# Filtrer par club
if fuzzy_match:
# Recherche floue: contient le nom
mask = df['club'].str.contains(club_name, case=False, na=False)
else:
# Recherche exacte
mask = df['club'].str.lower() == club_name.lower()
club_results = df[mask]
if len(club_results) == 0:
print(f"\n✗ Aucun résultat trouvé pour '{club_name}'")
print(f"\n💡 Suggestions:")
print(" - Vérifiez l'orthographe exacte du club")
print(" - Essayez une recherche partielle avec --fuzzy-match")
print(" - Utilisez --list-clubs pour voir tous les clubs disponibles")
return None
print(f"{len(club_results)} résultats trouvés")
# Afficher les variantes de noms de club trouvées
club_variants = club_results['club'].unique()
if len(club_variants) > 1:
print(f"\n📋 Variantes du nom trouvées ({len(club_variants)}):")
for variant in sorted(club_variants):
count = len(club_results[club_results['club'] == variant])
print(f" - {variant} ({count} résultats)")
# Statistiques
athletes = club_results[['nom', 'prenom']].drop_duplicates()
print(f"\n📊 Statistiques:")
print(f" - Athlètes différents: {len(athletes)}")
print(f" - Courses différentes: {len(club_results['course_nom'].unique())}")
print(f" - Dates couvertes: {club_results['course_date'].min()} à {club_results['course_date'].max()}")
return club_results
def export_club_results(club_results, club_name, output_dir="data/exports"):
"""Exporter les résultats d'un club en CSV"""
os.makedirs(output_dir, exist_ok=True)
# Nom du fichier de sortie
safe_name = club_name.replace('/', '-').replace('\\', '-').replace(' ', '_')
timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
filename = f"club_{safe_name}_{timestamp}.csv"
filepath = os.path.join(output_dir, filename)
# Sauvegarder
club_results.to_csv(filepath, index=False, encoding='utf-8-sig')
print(f"\n💾 Exporté: {filepath}")
print(f" {len(club_results)} lignes")
return filepath
def list_unique_clubs(results_file="data/results_daily.csv", search_term=None, limit=50):
"""Lister tous les clubs uniques dans les résultats"""
print(f"Lecture des clubs depuis {results_file}...")
try:
df = pd.read_csv(results_file, encoding='utf-8-sig')
except Exception as e:
print(f"✗ Erreur lecture CSV: {e}")
return
if search_term:
clubs = df[df['club'].str.contains(search_term, case=False, na=False)]['club'].unique()
print(f"\n📋 Clubs contenant '{search_term}' ({len(clubs)} trouvés):")
else:
clubs = df['club'].unique()
print(f"\n📋 Liste des clubs ({len(clubs)} clubs):")
# Trier et limiter l'affichage
clubs_sorted = sorted(clubs)[:limit] if limit else sorted(clubs)
for i, club in enumerate(clubs_sorted, 1):
count = len(df[df['club'] == club])
print(f" {i:3d}. {club} ({count} résultats)")
if len(clubs) > limit:
print(f"\n... et {len(clubs) - limit} autres clubs")
print(f"Utilisez --search-term pour filtrer")
def main():
parser = argparse.ArgumentParser(
description='Récupérer tous les résultats d\'un club FFA',
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Exemples:
# Résultats du club Haute Saintonge Athletisme
python get_club_results.py --club "Haute Saintonge Athletisme"
# Recherche floue
python get_club_results.py --club "Saintonge" --fuzzy-match
# Liste tous les clubs contenant "Saintonge"
python get_club_results.py --list-clubs --search-term "Saintonge"
# Sauvegarder dans un fichier spécifique
python get_club_results.py --club "Paris Athletic" --output custom_output.csv
"""
)
parser.add_argument('--club', type=str,
help='Nom du club à rechercher')
parser.add_argument('--fuzzy-match', action='store_true', default=True,
help='Recherche floue (contient le nom, défaut: True)')
parser.add_argument('--exact-match', action='store_true',
help='Recherche exacte (désactive fuzzy-match)')
parser.add_argument('--export', action='store_true', default=True,
help='Exporter en CSV (défaut: True)')
parser.add_argument('--list-clubs', action='store_true',
help='Lister tous les clubs disponibles')
parser.add_argument('--search-term', type=str,
help='Terme de recherche pour lister les clubs')
parser.add_argument('--limit', type=int, default=50,
help='Limiter le nombre de clubs affichés (défaut: 50)')
parser.add_argument('--output-dir', default='data/exports',
help='Répertoire de sortie pour les exports')
parser.add_argument('--results-file', default='data/results_daily.csv',
help='Fichier CSV des résultats')
parser.add_argument('--output', type=str,
help='Nom du fichier de sortie (si --export)')
args = parser.parse_args()
# Si recherche exacte, désactiver fuzzy match
if args.exact_match:
args.fuzzy_match = False
# Lister les clubs
if args.list_clubs:
list_unique_clubs(args.results_file, args.search_term, args.limit)
return
# Vérifier qu'un nom de club est fourni
if not args.club:
parser.error("--club est requis (sauf si --list-clubs est utilisé)")
print("=" * 70)
print("🏃 Récupération des résultats par club FFA")
print("=" * 70)
# Récupérer les résultats
club_results = get_club_results(
args.club,
args.results_file,
args.output_dir,
args.fuzzy_match
)
if club_results is None or len(club_results) == 0:
return
# Exporter si demandé
if args.export:
if args.output:
# Utiliser le nom de fichier spécifié
os.makedirs(args.output_dir, exist_ok=True)
filepath = os.path.join(args.output_dir, args.output)
club_results.to_csv(filepath, index=False, encoding='utf-8-sig')
print(f"\n💾 Exporté: {filepath}")
else:
export_club_results(club_results, args.club, args.output_dir)
print("\n✅ Terminé!")
if __name__ == "__main__":
main()