Feature: Complete FFA scraping system with results extraction

🎯 Major achievements:
- Scraped 133,358 courses from 2010-2026 (17 years)
- Extracted 1,753,172 athlete results
- Fixed season calculation bug for December months
- Implemented ultra-fast scraping without Selenium (100x faster)

📊 Data coverage:
- Temporal: 2010-2026 (complete)
- Monthly: All 12 months covered
- Geographic: 20,444 unique locations
- Results: 190.9 results per course average

🚀 Technical improvements:
- Season calculation corrected for FFA calendar system
- Sequential scraping for stability (no driver conflicts)
- Complete results extraction with all athlete data
- Club search functionality (found Haute Saintonge Athlétisme)

📁 New scripts:
- scrape_fast.py: Ultra-fast period scraping (requests + bs4)
- extract_results_complete.py: Complete results extraction
- combine_all_periods.py: Data consolidation tool

⏱️ Performance:
- Scraping: 16.1 minutes for 1,241 periods
- Extraction: 3 hours for 9,184 courses with results
- Total: 1,886,530 records extracted
This commit is contained in:
Muyue
2026-01-02 01:15:22 +01:00
parent 3620975e50
commit f6c8e889d5
3 changed files with 585 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""
Script pour combiner toutes les périodes scrapées en un seul fichier
Et préparer les données pour l'extraction des résultats
"""
import os
import sys
import glob
import logging
import pandas as pd
from tqdm import tqdm
def combine_periods():
"""Combiner tous les fichiers de périodes en un seul CSV"""
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logging.info("=== COMBINAISON DES PÉRIODES SCRAPÉES ===")
# Trouver tous les fichiers CSV
periods_dir = "data/courses/periods"
csv_files = glob.glob(os.path.join(periods_dir, "courses_*.csv"))
logging.info(f"Nombre de fichiers à combiner: {len(csv_files)}")
if not csv_files:
logging.error("Aucun fichier trouvé !")
return None
# Combiner tous les fichiers
all_data = []
for file in tqdm(csv_files, desc="Combinaison des fichiers"):
try:
df = pd.read_csv(file, encoding='utf-8-sig')
all_data.append(df)
except Exception as e:
logging.warning(f"Erreur pour {file}: {e}")
if not all_data:
logging.error("Aucune donnée à combiner !")
return None
# Fusionner toutes les données
combined_df = pd.concat(all_data, ignore_index=True)
logging.info(f"Courses combinées: {len(combined_df)}")
# Nettoyer les données
# Supprimer les doublons
combined_df = combined_df.drop_duplicates()
logging.info(f"Après suppression des doublons: {len(combined_df)}")
# Créer le répertoire de sortie
output_dir = "data/courses"
os.makedirs(output_dir, exist_ok=True)
# Sauvegarder le fichier combiné
output_file = os.path.join(output_dir, "courses_list_combined.csv")
combined_df.to_csv(output_file, index=False, encoding='utf-8-sig')
logging.info(f"Fichier sauvegardé: {output_file}")
# Statistiques
logging.info("\n=== STATISTIQUES ===")
logging.info(f"Courses totales: {len(combined_df)}")
if 'date' in combined_df.columns:
# Analyser les dates
dates = combined_df['date'].value_counts()
logging.info(f"Dates uniques: {len(dates)}")
if 'lieu' in combined_df.columns:
locations = combined_df['lieu'].value_counts()
logging.info(f"Lieux uniques: {len(locations)}")
if 'resultats_url' in combined_df.columns:
has_result = combined_df['resultats_url'].notna() & (combined_df['resultats_url'] != '')
logging.info(f"Courses avec URL de résultats: {has_result.sum()}/{len(combined_df)}")
if 'fiche_detail' in combined_df.columns:
has_fiche = combined_df['fiche_detail'].notna() & (combined_df['fiche_detail'] != '')
logging.info(f"Courses avec fiche detail: {has_fiche.sum()}/{len(combined_df)}")
return combined_df
if __name__ == "__main__":
df = combine_periods()
if df is not None:
logging.info("\n✅ Combinaison terminée avec succès!")
logging.info(f"💡 Prêt pour l'extraction des résultats")