#!/usr/bin/env python3 """ Script pour rechercher une course dans les données FFA Peut utiliser les fichiers CSV ou chercher directement depuis l'URL FFA """ import pandas as pd import os import sys import argparse import logging sys.path.insert(0, os.path.join(os.path.dirname(__file__), '../src')) from ffa_scraper import FFAScraper from datetime import datetime logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s' ) def search_race_by_name_csv(nom_course, data_dir="data"): """Rechercher une course par nom dans les fichiers CSV""" courses_path = os.path.join(data_dir, 'courses', 'courses_list.csv') if not os.path.exists(courses_path): logging.error(f"Fichier de courses introuvable: {courses_path}") return [] try: df = pd.read_csv(courses_path, encoding='utf-8-sig') mask = df['nom'].str.contains(nom_course, case=False, na=False) courses = df[mask].to_dict('records') logging.info(f"Trouvé {len(courses)} courses correspondant à '{nom_course}'") return courses except Exception as e: logging.error(f"Erreur lors de la recherche dans les CSV: {e}") return [] def search_race_by_date_csv(start_date, end_date=None, data_dir="data"): """Rechercher des courses par date dans les fichiers CSV""" courses_path = os.path.join(data_dir, 'courses', 'courses_list.csv') if not os.path.exists(courses_path): logging.error(f"Fichier de courses introuvable: {courses_path}") return [] try: df = pd.read_csv(courses_path, encoding='utf-8-sig') # Convertir les dates df['date'] = pd.to_datetime(df['date'], errors='coerce') if end_date: mask = (df['date'] >= pd.to_datetime(start_date)) & (df['date'] <= pd.to_datetime(end_date)) else: mask = df['date'] == pd.to_datetime(start_date) courses = df[mask].sort_values('date').to_dict('records') logging.info(f"Trouvé {len(courses)} courses dans la période") return courses except Exception as e: logging.error(f"Erreur lors de la recherche par date: {e}") return [] def search_race_by_type_csv(type_course, data_dir="data"): """Rechercher des courses par type dans les fichiers CSV""" courses_path = os.path.join(data_dir, 'courses', 'courses_list.csv') if not os.path.exists(courses_path): logging.error(f"Fichier de courses introuvable: {courses_path}") return [] try: df = pd.read_csv(courses_path, encoding='utf-8-sig') mask = df['type'].str.contains(type_course, case=False, na=False) courses = df[mask].to_dict('records') logging.info(f"Trouvé {len(courses)} courses de type '{type_course}'") return courses except Exception as e: logging.error(f"Erreur lors de la recherche par type: {e}") return [] def search_race_by_location_csv(lieu, data_dir="data"): """Rechercher des courses par lieu dans les fichiers CSV""" courses_path = os.path.join(data_dir, 'courses', 'courses_list.csv') if not os.path.exists(courses_path): logging.error(f"Fichier de courses introuvable: {courses_path}") return [] try: df = pd.read_csv(courses_path, encoding='utf-8-sig') mask = df['lieu'].str.contains(lieu, case=False, na=False) courses = df[mask].to_dict('records') logging.info(f"Trouvé {len(courses)} courses à '{lieu}'") return courses except Exception as e: logging.error(f"Erreur lors de la recherche par lieu: {e}") return [] def search_race_live(search_term, search_type="name", max_pages=5): """Rechercher une course en direct depuis le site FFA""" scraper = FFAScraper() logging.info(f"Recherche en direct de courses (type: {search_type})...") logging.warning("Note: Cela peut prendre du temps") # Récupérer les courses total_pages, total_courses, _ = scraper._detect_pagination_info() if not total_pages: logging.error("Impossible de détecter les données") return [] max_pages = min(max_pages, total_pages) logging.info(f"Analyse de {max_pages} pages...") courses = scraper.get_courses_list(max_pages=max_pages, use_multithreading=True) # Filtrer selon le type de recherche filtered_courses = [] for course in courses: match = False if search_type == "name": match = search_term.lower() in course.get('nom', '').lower() elif search_type == "type": match = search_term.lower() in course.get('type', '').lower() elif search_type == "location": match = search_term.lower() in course.get('lieu', '').lower() if match: filtered_courses.append(course) logging.info(f"Trouvé {len(filtered_courses)} courses en direct") return filtered_courses def display_race_results(courses, show_details=False, limit=None): """Afficher les résultats de recherche de courses""" if not courses: print("\n❌ Aucune course trouvée") return print(f"\n{'='*80}") print(f"📅 RÉSULTATS DE LA RECHERCHE ({len(courses)} courses trouvées)") print(f"{'='*80}\n") if limit: courses = courses[:limit] for i, course in enumerate(courses, 1): print(f"{i}. {course.get('nom', 'Inconnu')}") if course.get('date'): print(f" 📅 Date: {course['date']}") if course.get('lieu'): print(f" 📍 Lieu: {course['lieu']}") if course.get('type'): print(f" 🏷️ Type: {course['type']}") if course.get('niveau'): print(f" 📊 Niveau: {course['niveau']}") if show_details: if course.get('discipline'): print(f" 🎯 Discipline: {course['discipline']}") if course.get('fiche_detail'): print(f" 🔗 Détails: {course['fiche_detail']}") if course.get('resultats_url'): print(f" 🏆 Résultats: {course['resultats_url']}") if course.get('page'): print(f" 📄 Page: {course['page']}") print() print(f"{'='*80}") def export_race_csv(courses, filename, output_dir="data"): """Exporter les résultats de recherche en CSV""" os.makedirs(os.path.join(output_dir, 'exports'), exist_ok=True) filepath = os.path.join(output_dir, 'exports', filename.replace(" ", "_")) df = pd.DataFrame(courses) df.to_csv(filepath, index=False, encoding='utf-8-sig') logging.info(f"Exporté {len(courses)} courses dans {filepath}") return filepath def main(): parser = argparse.ArgumentParser(description='Rechercher une course dans les données FFA') parser.add_argument('--csv', action='store_true', default=True, help='Utiliser les fichiers CSV existants (défaut)') parser.add_argument('--live', action='store_true', help='Récupérer les données en direct depuis le site FFA') parser.add_argument('--data-dir', default='data', help='Répertoire des données CSV') parser.add_argument('--max-pages', type=int, default=5, help='Nombre maximum de pages à scraper en mode live (défaut: 5)') parser.add_argument('--details', action='store_true', help='Afficher les détails complets') parser.add_argument('--limit', type=int, help='Limiter le nombre de courses affichées') parser.add_argument('--export', action='store_true', help='Exporter les résultats en CSV') parser.add_argument('--export-filename', help='Nom du fichier CSV exporté') # Critères de recherche parser.add_argument('--name', help='Rechercher par nom de course') parser.add_argument('--location', help='Rechercher par lieu') parser.add_argument('--type', help='Rechercher par type de course') parser.add_argument('--start-date', help='Date de début (format: YYYY-MM-DD)') parser.add_argument('--end-date', help='Date de fin (format: YYYY-MM-DD)') args = parser.parse_args() # Vérifier qu'au moins un critère de recherche est fourni if not any([args.name, args.location, args.type, args.start_date]): parser.error("Au moins un critère de recherche est requis (--name, --location, --type, --start-date)") # Recherche courses = [] if args.live: # Mode live if args.name: print(f"\n🔍 Mode live: recherche de courses par nom '{args.name}'...") courses = search_race_live(args.name, "name", args.max_pages) elif args.type: print(f"\n🔍 Mode live: recherche de courses par type '{args.type}'...") courses = search_race_live(args.type, "type", args.max_pages) elif args.location: print(f"\n🔍 Mode live: recherche de courses par lieu '{args.location}'...") courses = search_race_live(args.location, "location", args.max_pages) else: # Mode CSV print(f"\n📂 Mode CSV: recherche dans {args.data_dir}/") if args.name: courses = search_race_by_name_csv(args.name, args.data_dir) elif args.location: courses = search_race_by_location_csv(args.location, args.data_dir) elif args.type: courses = search_race_by_type_csv(args.type, args.data_dir) elif args.start_date: courses = search_race_by_date_csv(args.start_date, args.end_date, args.data_dir) # Affichage display_race_results(courses, show_details=args.details, limit=args.limit) # Export if args.export and courses: if args.export_filename: filename = args.export_filename else: filename = f"race_search_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv" filepath = export_race_csv(courses, filename, args.data_dir) print(f"\n💾 Exporté dans: {filepath}") if __name__ == "__main__": main()