- 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
219 lines
7.4 KiB
Python
Executable File
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()
|