Files
ffa-calendar/scripts/search_athlete.py
Muyue a5406a4e89 Initial commit: Reorganiser le projet FFA Calendar Scraper
- Créer une arborescence propre (src/, scripts/, config/, data/, docs/, tests/)
- Déplacer les modules Python dans src/
- Déplacer les scripts autonomes dans scripts/
- Nettoyer les fichiers temporaires et __pycache__
- Mettre à jour le README.md avec documentation complète
- Mettre à jour les imports dans les scripts pour la nouvelle structure
- Configurer le .gitignore pour ignorer les données et logs
- Organiser les données dans data/ (courses, resultats, clubs, exports)

Structure du projet:
- src/: Modules principaux (ffa_scraper, ffa_analyzer)
- scripts/: Scripts CLI et utilitaires
- config/: Configuration (config.env)
- data/: Données générées
- docs/: Documentation
- tests/: Tests unitaires

💘 Generated with Crush

Assisted-by: GLM-4.7 via Crush <crush@charm.land>
2026-01-01 18:05:14 +01:00

216 lines
7.6 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Script pour rechercher un athlète dans les résultats 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 ffa_analyzer import FFADataAnalyzer
from datetime import datetime
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
def search_athlete_csv(nom, prenom=None, data_dir="data"):
"""Rechercher un athlète dans les fichiers CSV"""
results_path = os.path.join(data_dir, 'resultats', 'results.csv')
if not os.path.exists(results_path):
logging.error(f"Fichier de résultats introuvable: {results_path}")
return []
try:
df = pd.read_csv(results_path, encoding='utf-8-sig')
# Filtre par nom (obligatoire)
mask = df['nom'].str.contains(nom, case=False, na=False)
# Filtre par prénom (optionnel)
if prenom:
mask &= df['prenom'].str.contains(prenom, case=False, na=False)
results = df[mask].to_dict('records')
logging.info(f"Trouvé {len(results)} résultats pour {nom} {prenom or ''}")
return results
except Exception as e:
logging.error(f"Erreur lors de la recherche dans les CSV: {e}")
return []
def search_athlete_live(nom, prenom=None, max_pages=5):
"""Rechercher un athlète en direct depuis le site FFA"""
scraper = FFAScraper()
logging.info(f"Recherche en direct pour {nom} {prenom or ''}...")
logging.warning("Note: Cela peut prendre du temps car il faut scraper les résultats")
# Récupérer les courses et leurs résultats
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...")
all_results = []
courses = scraper.get_courses_list(max_pages=max_pages, use_multithreading=True)
for course in courses:
if course.get('resultats_url'):
results = scraper.get_course_results(course['resultats_url'])
# Filtrer les résultats pour cet athlète
for result in results:
match_nom = nom.lower() in result.get('nom', '').lower()
match_prenom = not prenom or prenom.lower() in result.get('prenom', '').lower()
if match_nom and match_prenom:
# Ajouter des infos de la course
result['course_nom'] = course.get('nom', '')
result['course_date'] = course.get('date', '')
result['course_lieu'] = course.get('lieu', '')
all_results.append(result)
logging.info(f"Trouvé {len(all_results)} résultats en direct")
return all_results
def display_athlete_results(results, show_details=False, limit=None):
"""Afficher les résultats d'un athlète"""
if not results:
print("\n❌ Aucun résultat trouvé pour cet athlète")
return
# Identifier l'athlète
athlete_nom = results[0].get('nom', 'Inconnu')
athlete_prenom = results[0].get('prenom', '')
print(f"\n{'='*80}")
print(f"🏃 RÉSULTATS POUR {athlete_prenom} {athlete_nom}")
print(f"{'='*80}\n")
if limit:
results = results[:limit]
# Afficher les informations générales
print(f"Club: {results[0].get('club', 'Inconnu')}")
print(f"Total des courses: {len(results)}")
if show_details:
# Calculer des statistiques
podiums = 0
victoires = 0
places = []
for result in results:
try:
place = int(result.get('place', 0))
if place == 1:
victoires += 1
podiums += 1
elif place <= 3:
podiums += 1
places.append(place)
except:
pass
print(f"Victoires: {victoires}")
print(f"Podiums: {podiums}")
if places:
avg_place = sum(places) / len(places)
print(f"Place moyenne: {avg_place:.2f}")
print(f"\n{'='*80}\n")
# Afficher les résultats individuels
print(f"{'📋 LISTE DES COURSES':<}")
print(f"{'='*80}\n")
for i, result in enumerate(results, 1):
print(f"{i}. {result.get('course_nom', result.get('course_url', 'Inconnu'))}")
if result.get('course_date'):
print(f" 📅 Date: {result['course_date']}")
if result.get('course_lieu'):
print(f" 📍 Lieu: {result['course_lieu']}")
print(f" 🏆 Place: {result.get('place', 'N/A')}")
print(f" ⏱️ Temps: {result.get('temps', result.get('resultat', 'N/A'))}")
print(f" 🏷️ Catégorie: {result.get('categorie', 'N/A')}")
if show_details:
if result.get('points'):
print(f" 🎯 Points: {result['points']}")
if result.get('niveau'):
print(f" 📊 Niveau: {result['niveau']}")
print()
print(f"{'='*80}")
def export_results_csv(results, nom, prenom=None, output_dir="data"):
"""Exporter les résultats d'un athlète en CSV"""
os.makedirs(os.path.join(output_dir, 'exports'), exist_ok=True)
if prenom:
filename = f"athlete_{nom}_{prenom}_results.csv"
else:
filename = f"athlete_{nom}_results.csv"
filepath = os.path.join(output_dir, 'exports', filename.replace(" ", "_"))
df = pd.DataFrame(results)
df.to_csv(filepath, index=False, encoding='utf-8-sig')
logging.info(f"Exporté {len(results)} résultats dans {filepath}")
return filepath
def main():
parser = argparse.ArgumentParser(description='Rechercher un athlète dans les résultats FFA')
parser.add_argument('nom', help='Nom de l\'athlète à rechercher')
parser.add_argument('--prenom', help='Prénom de l\'athlète (optionnel)')
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 résultats affichés')
parser.add_argument('--export', action='store_true',
help='Exporter les résultats en CSV')
args = parser.parse_args()
# Recherche
if args.live:
print(f"\n🔍 Mode live: recherche en direct sur le site FFA...")
results = search_athlete_live(args.nom, args.prenom, args.max_pages)
else:
print(f"\n📂 Mode CSV: recherche dans {args.data_dir}/")
results = search_athlete_csv(args.nom, args.prenom, args.data_dir)
# Affichage
display_athlete_results(results, show_details=args.details, limit=args.limit)
# Export
if args.export and results:
filepath = export_results_csv(results, args.nom, args.prenom, args.data_dir)
print(f"\n💾 Exporté dans: {filepath}")
if __name__ == "__main__":
main()