601 lines
24 KiB
Python
601 lines
24 KiB
Python
#!/usr/bin/env python3
|
||
"""
|
||
Démonstration des améliorations du scraper agenda du libre
|
||
Simule les fonctionnalités sans dépendances externes
|
||
"""
|
||
|
||
import json
|
||
import os
|
||
import sys
|
||
import re
|
||
import time
|
||
from datetime import datetime
|
||
import hashlib
|
||
|
||
class DemoAgendaDuLibreScraper:
|
||
def __init__(self, max_events=None, dry_run=True, parallel=False, max_workers=4):
|
||
self.max_events = max_events
|
||
self.dry_run = dry_run
|
||
self.parallel = parallel
|
||
self.max_workers = max_workers
|
||
self.cache_file = "demo_agendadulibre_cache.json"
|
||
self.events_file = "demo_agendadulibre_events.json"
|
||
|
||
# Charger les données existantes
|
||
self.cache_data = self.load_cache_data()
|
||
self.events_data = self.load_events_data()
|
||
|
||
def load_cache_data(self):
|
||
"""Charge les données de cache"""
|
||
if os.path.exists(self.cache_file):
|
||
try:
|
||
with open(self.cache_file, 'r', encoding='utf-8') as f:
|
||
return json.load(f)
|
||
except Exception as e:
|
||
print(f"Erreur lors du chargement du cache: {e}")
|
||
return {"processed_events": {}, "last_fetch": None, "content_hash": None}
|
||
|
||
def load_events_data(self):
|
||
"""Charge les données d'événements"""
|
||
if os.path.exists(self.events_file):
|
||
try:
|
||
with open(self.events_file, 'r', encoding='utf-8') as f:
|
||
return json.load(f)
|
||
except Exception as e:
|
||
print(f"Erreur lors du chargement des événements: {e}")
|
||
return {"events": {}, "last_update": None}
|
||
|
||
def save_cache_data(self):
|
||
"""Sauvegarde le cache"""
|
||
try:
|
||
with open(self.cache_file, 'w', encoding='utf-8') as f:
|
||
json.dump(self.cache_data, f, ensure_ascii=False, indent=2)
|
||
except Exception as e:
|
||
print(f"Erreur lors de la sauvegarde du cache: {e}")
|
||
|
||
def save_events_data(self):
|
||
"""Sauvegarde les événements"""
|
||
try:
|
||
with open(self.events_file, 'w', encoding='utf-8') as f:
|
||
json.dump(self.events_data, f, ensure_ascii=False, indent=2)
|
||
except Exception as e:
|
||
print(f"Erreur lors de la sauvegarde des événements: {e}")
|
||
|
||
def get_content_hash(self, content):
|
||
"""Calcule le hash du contenu"""
|
||
return hashlib.md5(content.encode('utf-8')).hexdigest()
|
||
|
||
def simulate_ical_fetch(self):
|
||
"""Simule la récupération d'un fichier iCal"""
|
||
# Simuler du contenu iCal
|
||
ical_content = f"""
|
||
BEGIN:VCALENDAR
|
||
VERSION:2.0
|
||
PRODID:-//Demo//Agenda du Libre//EN
|
||
BEGIN:VEVENT
|
||
UID:event1@demo.com
|
||
DTSTART:20241201T100000Z
|
||
DTEND:20241201T120000Z
|
||
SUMMARY:Conférence Python
|
||
DESCRIPTION:Présentation sur Python
|
||
LOCATION:Paris, France
|
||
URL:https://example.com/event1
|
||
END:VEVENT
|
||
BEGIN:VEVENT
|
||
UID:event2@demo.com
|
||
DTSTART:20241202T140000Z
|
||
DTEND:20241202T160000Z
|
||
SUMMARY:Atelier Linux
|
||
DESCRIPTION:Apprendre Linux
|
||
LOCATION:Lyon, France
|
||
URL:https://example.com/event2
|
||
END:VEVENT
|
||
BEGIN:VEVENT
|
||
UID:event3@demo.com
|
||
DTSTART:20241203T090000Z
|
||
DTEND:20241203T110000Z
|
||
SUMMARY:Formation Git
|
||
DESCRIPTION:Maîtriser Git
|
||
LOCATION:Marseille, France
|
||
URL:https://example.com/event3
|
||
END:VEVENT
|
||
BEGIN:VEVENT
|
||
UID:event4@demo.com
|
||
DTSTART:20241204T130000Z
|
||
DTEND:20241204T150000Z
|
||
SUMMARY:Meetup DevOps
|
||
DESCRIPTION:Discussion DevOps
|
||
LOCATION:Toulouse, France
|
||
URL:https://example.com/event4
|
||
END:VEVENT
|
||
BEGIN:VEVENT
|
||
UID:event5@demo.com
|
||
DTSTART:20241205T100000Z
|
||
DTEND:20241205T120000Z
|
||
SUMMARY:Workshop Docker
|
||
DESCRIPTION:Conteneurisation
|
||
LOCATION:Nice, France
|
||
URL:https://example.com/event5
|
||
END:VEVENT
|
||
END:VCALENDAR
|
||
"""
|
||
return ical_content
|
||
|
||
def extract_geo_coordinates(self, event_data):
|
||
"""Simule l'extraction des coordonnées GEO"""
|
||
# Simuler des coordonnées GEO pour certains événements
|
||
geo_simulation = {
|
||
"Centre de conférences, 15 rue de la Paix, Paris, France": [2.3522, 48.8566],
|
||
"Espace formation, 42 avenue du Général de Gaulle, Marseille, France": [5.3698, 43.2965]
|
||
}
|
||
|
||
location = event_data["location"]
|
||
if location in geo_simulation:
|
||
coords = geo_simulation[location]
|
||
print(f"📍 Coordonnées GEO trouvées: {coords[1]}, {coords[0]}")
|
||
return coords
|
||
else:
|
||
print("Aucun champ GEO trouvé")
|
||
return None
|
||
|
||
def extract_categories(self, event_data):
|
||
"""Simule l'extraction des catégories"""
|
||
# Simuler des catégories pour certains événements
|
||
categories_simulation = {
|
||
"Centre de conférences, 15 rue de la Paix, Paris, France": ["python", "programmation", "conférence"],
|
||
"Espace formation, 42 avenue du Général de Gaulle, Marseille, France": ["git", "formation", "développement"],
|
||
"Lyon, France": ["linux", "atelier", "entraide"],
|
||
"Toulouse, France": ["devops", "meetup", "discussion"],
|
||
"Nice, France": ["docker", "workshop", "conteneurisation"]
|
||
}
|
||
|
||
location = event_data["location"]
|
||
if location in categories_simulation:
|
||
categories = categories_simulation[location]
|
||
print(f"🏷️ Catégories trouvées: {', '.join(categories)}")
|
||
return categories
|
||
else:
|
||
print("Aucune catégorie trouvée")
|
||
return []
|
||
|
||
def extract_organizer(self, event_data):
|
||
"""Simule l'extraction de l'organisateur"""
|
||
organizers_simulation = {
|
||
"Centre de conférences, 15 rue de la Paix, Paris, France": "mailto:contact@python.org",
|
||
"Espace formation, 42 avenue du Général de Gaulle, Marseille, France": "mailto:formation@git.org",
|
||
"Lyon, France": "mailto:contact@aldil.org",
|
||
"Toulouse, France": "mailto:devops@toulouse.org",
|
||
"Nice, France": "mailto:docker@nice.org"
|
||
}
|
||
|
||
location = event_data["location"]
|
||
if location in organizers_simulation:
|
||
organizer = organizers_simulation[location]
|
||
print(f"👤 Organisateur trouvé: {organizer}")
|
||
return organizer
|
||
else:
|
||
print("Aucun organisateur trouvé")
|
||
return None
|
||
|
||
def extract_alt_description(self, event_data):
|
||
"""Simule l'extraction de la description alternative HTML"""
|
||
# Simuler une description HTML pour certains événements
|
||
if "Centre de conférences" in event_data["location"]:
|
||
alt_desc = "<p>Conférence sur <strong>Python</strong> avec présentation des nouveautés</p>"
|
||
print(f"📄 Description alternative HTML trouvée: {len(alt_desc)} caractères")
|
||
return alt_desc
|
||
return None
|
||
|
||
def extract_short_description(self, event_data):
|
||
"""Simule l'extraction de la description courte"""
|
||
summary = event_data["summary"]
|
||
print(f"📝 Description courte trouvée: {summary}")
|
||
return summary
|
||
|
||
def extract_sequence(self, event_data):
|
||
"""Simule l'extraction de la séquence"""
|
||
# Simuler des numéros de séquence
|
||
sequences = [1, 2, 3, 4, 5]
|
||
seq_num = sequences[len(event_data["summary"]) % len(sequences)]
|
||
print(f"🔢 Séquence trouvée: {seq_num}")
|
||
return seq_num
|
||
|
||
def extract_repeat_rules(self, event_data):
|
||
"""Simule l'extraction des règles de répétition"""
|
||
# Simuler des règles de répétition pour certains événements
|
||
if "Atelier" in event_data["summary"]:
|
||
rrule = "FREQ=WEEKLY;BYDAY=TU"
|
||
print(f"🔄 Règles de répétition trouvées: {rrule}")
|
||
return rrule
|
||
elif "Workshop" in event_data["summary"]:
|
||
rrule = "FREQ=MONTHLY;BYDAY=1SA"
|
||
print(f"🔄 Règles de répétition trouvées: {rrule}")
|
||
return rrule
|
||
return None
|
||
|
||
def parse_event(self, event_data):
|
||
"""Parse un événement simulé"""
|
||
# Extraire les coordonnées GEO si disponibles
|
||
geo_coords = self.extract_geo_coordinates(event_data)
|
||
|
||
# Extraire les catégories si disponibles
|
||
categories = self.extract_categories(event_data)
|
||
|
||
# Extraire les propriétés supplémentaires
|
||
organizer = self.extract_organizer(event_data)
|
||
alt_description = self.extract_alt_description(event_data)
|
||
short_description = self.extract_short_description(event_data)
|
||
sequence = self.extract_sequence(event_data)
|
||
repeat_rules = self.extract_repeat_rules(event_data)
|
||
|
||
return {
|
||
"id": hashlib.md5(event_data["summary"].encode('utf-8')).hexdigest(),
|
||
"event": {
|
||
"properties": {
|
||
"label": event_data["summary"],
|
||
"description": event_data["description"],
|
||
"type": "scheduled",
|
||
"what": "culture.floss",
|
||
"where": event_data["location"],
|
||
"start": event_data["start"],
|
||
"stop": event_data["end"],
|
||
"url": event_data["url"],
|
||
"source:name": "Agenda du Libre (Demo)",
|
||
"source:url": "https://www.agendadulibre.org/",
|
||
"last_modified_by": "demo_scraper",
|
||
"tags": categories if categories else [],
|
||
"organizer": organizer,
|
||
"alt_description": alt_description,
|
||
"short_description": short_description,
|
||
"sequence": sequence,
|
||
"repeat_rules": repeat_rules
|
||
},
|
||
"geometry": {
|
||
"type": "Point",
|
||
"coordinates": geo_coords if geo_coords else [0, 0]
|
||
}
|
||
},
|
||
"raw_ical": {
|
||
"geo": geo_coords,
|
||
"categories": categories,
|
||
"organizer": organizer,
|
||
"alt_description": alt_description,
|
||
"short_description": short_description,
|
||
"sequence": sequence,
|
||
"repeat_rules": repeat_rules
|
||
}
|
||
}
|
||
|
||
def clean_location_for_geocoding(self, location):
|
||
"""Nettoie le lieu pour le géocodage en extrayant l'adresse après la première virgule"""
|
||
if not location or location.strip() == "":
|
||
return None
|
||
|
||
# Diviser par la première virgule
|
||
parts = location.split(',', 1)
|
||
if len(parts) > 1:
|
||
# Prendre la partie après la première virgule
|
||
address_part = parts[1].strip()
|
||
|
||
# Vérifier si on a un numéro et une adresse
|
||
# Pattern pour détecter un numéro suivi d'une adresse
|
||
address_pattern = r'^\s*\d+.*'
|
||
if re.match(address_pattern, address_part):
|
||
print(f"📍 Adresse potentielle trouvée: {address_part}")
|
||
return address_part
|
||
|
||
# Si pas de virgule ou pas d'adresse valide, essayer le lieu complet
|
||
print(f"📍 Tentative de géocodage avec le lieu complet: {location}")
|
||
return location.strip()
|
||
|
||
def simulate_geocoding(self, location):
|
||
"""Simule le géocodage avec des coordonnées fictives"""
|
||
if not location:
|
||
return None
|
||
|
||
# Simulation de coordonnées basées sur le lieu
|
||
fake_coords = {
|
||
"Paris": [2.3522, 48.8566],
|
||
"Lyon": [4.8357, 45.7640],
|
||
"Marseille": [5.3698, 43.2965],
|
||
"Toulouse": [1.4442, 43.6047],
|
||
"Nice": [7.2619, 43.7102],
|
||
"Nantes": [-1.5536, 47.2184],
|
||
"Strasbourg": [7.7521, 48.5734],
|
||
"Montpellier": [3.8767, 43.6110],
|
||
"Bordeaux": [-0.5792, 44.8378],
|
||
"Lille": [3.0573, 50.6292]
|
||
}
|
||
|
||
# Chercher une correspondance dans les villes connues
|
||
for city, coords in fake_coords.items():
|
||
if city.lower() in location.lower():
|
||
print(f"🌍 Géocodage simulé: {location} -> {coords}")
|
||
return coords
|
||
|
||
# Coordonnées par défaut si pas de correspondance
|
||
default_coords = [2.3522, 48.8566] # Paris par défaut
|
||
print(f"🌍 Géocodage simulé (défaut): {location} -> {default_coords}")
|
||
return default_coords
|
||
|
||
def improve_event_coordinates(self, event_data):
|
||
"""Améliore les coordonnées de l'événement si nécessaire"""
|
||
coords = event_data["event"]["geometry"]["coordinates"]
|
||
|
||
# Vérifier si les coordonnées sont par défaut (0, 0)
|
||
if coords == [0, 0]:
|
||
location = event_data["event"]["properties"].get("where", "")
|
||
|
||
if location:
|
||
# Nettoyer le lieu pour le géocodage
|
||
clean_location = self.clean_location_for_geocoding(location)
|
||
|
||
if clean_location:
|
||
# Tenter le géocodage simulé
|
||
new_coords = self.simulate_geocoding(clean_location)
|
||
|
||
if new_coords:
|
||
# Mettre à jour les coordonnées
|
||
event_data["event"]["geometry"]["coordinates"] = new_coords
|
||
print(f"🎯 Coordonnées mises à jour par géocodage: {coords} -> {new_coords}")
|
||
else:
|
||
print(f"⚠️ Impossible de géocoder: {clean_location}")
|
||
else:
|
||
print(f"ℹ️ Lieu non géocodable: {location}")
|
||
else:
|
||
print("ℹ️ Aucun lieu spécifié pour le géocodage")
|
||
else:
|
||
# Vérifier si les coordonnées viennent du champ GEO
|
||
geo_coords = event_data.get("raw_ical", {}).get("geo")
|
||
if geo_coords:
|
||
print(f"✅ Coordonnées utilisées depuis le champ GEO: {coords}")
|
||
else:
|
||
print(f"ℹ️ Coordonnées déjà définies: {coords}")
|
||
|
||
return event_data
|
||
|
||
def log_event_details(self, event_data):
|
||
"""Log détaillé de l'événement avant envoi"""
|
||
props = event_data["event"]["properties"]
|
||
geom = event_data["event"]["geometry"]
|
||
|
||
print("📝 Détails de l'événement à insérer:")
|
||
print(f" ID: {event_data['id']}")
|
||
print(f" Titre: {props.get('label', 'N/A')}")
|
||
print(f" Description: {props.get('description', 'N/A')[:100]}{'...' if len(props.get('description', '')) > 100 else ''}")
|
||
print(f" Type: {props.get('type', 'N/A')}")
|
||
print(f" Catégorie: {props.get('what', 'N/A')}")
|
||
print(f" Lieu: {props.get('where', 'N/A')}")
|
||
print(f" Début: {props.get('start', 'N/A')}")
|
||
print(f" Fin: {props.get('stop', 'N/A')}")
|
||
print(f" URL: {props.get('url', 'N/A')}")
|
||
print(f" Source: {props.get('source:name', 'N/A')}")
|
||
print(f" Coordonnées: {geom.get('coordinates', 'N/A')}")
|
||
print(f" Tags: {', '.join(props.get('tags', [])) if props.get('tags') else 'N/A'}")
|
||
print(f" Organisateur: {props.get('organizer', 'N/A')}")
|
||
print(f" Description courte: {props.get('short_description', 'N/A')}")
|
||
print(f" Séquence: {props.get('sequence', 'N/A')}")
|
||
print(f" Règles de répétition: {props.get('repeat_rules', 'N/A')}")
|
||
print(f" Description HTML: {'Oui' if props.get('alt_description') else 'N/A'}")
|
||
print(f" Modifié par: {props.get('last_modified_by', 'N/A')}")
|
||
|
||
def send_event_to_api(self, event_data, skip_geocoding=False):
|
||
"""Simule l'envoi à l'API"""
|
||
# Améliorer les coordonnées si nécessaire (sauf si déjà traité)
|
||
if not skip_geocoding:
|
||
event_data = self.improve_event_coordinates(event_data)
|
||
else:
|
||
print("ℹ️ Géocodage ignoré - événement déjà traité")
|
||
|
||
# Log détaillé de l'événement
|
||
self.log_event_details(event_data)
|
||
|
||
if self.dry_run:
|
||
print(f"[DRY-RUN] Simulation d'envoi: {event_data['event']['properties']['label']}")
|
||
return True, "Simulé (dry-run)"
|
||
else:
|
||
print(f"[API] Envoi réel: {event_data['event']['properties']['label']}")
|
||
return True, "Envoyé avec succès"
|
||
|
||
def process_events(self):
|
||
"""Traite les événements"""
|
||
# Simuler des événements avec des lieux variés pour tester le géocodage
|
||
events = [
|
||
{
|
||
"summary": "Conférence Python",
|
||
"description": "Présentation sur Python",
|
||
"location": "Centre de conférences, 15 rue de la Paix, Paris, France",
|
||
"start": "2024-12-01T10:00:00",
|
||
"end": "2024-12-01T12:00:00",
|
||
"url": "https://example.com/event1"
|
||
},
|
||
{
|
||
"summary": "Atelier Linux",
|
||
"description": "Apprendre Linux",
|
||
"location": "Lyon, France",
|
||
"start": "2024-12-02T14:00:00",
|
||
"end": "2024-12-02T16:00:00",
|
||
"url": "https://example.com/event2"
|
||
},
|
||
{
|
||
"summary": "Formation Git",
|
||
"description": "Maîtriser Git",
|
||
"location": "Espace formation, 42 avenue du Général de Gaulle, Marseille, France",
|
||
"start": "2024-12-03T09:00:00",
|
||
"end": "2024-12-03T11:00:00",
|
||
"url": "https://example.com/event3"
|
||
},
|
||
{
|
||
"summary": "Meetup DevOps",
|
||
"description": "Discussion DevOps",
|
||
"location": "Toulouse, France",
|
||
"start": "2024-12-04T13:00:00",
|
||
"end": "2024-12-04T15:00:00",
|
||
"url": "https://example.com/event4"
|
||
},
|
||
{
|
||
"summary": "Workshop Docker",
|
||
"description": "Conteneurisation",
|
||
"location": "Nice, France",
|
||
"start": "2024-12-05T10:00:00",
|
||
"end": "2024-12-05T12:00:00",
|
||
"url": "https://example.com/event5"
|
||
}
|
||
]
|
||
|
||
stats = {
|
||
"total_events": len(events),
|
||
"new_events": 0,
|
||
"already_saved": 0,
|
||
"api_errors": 0,
|
||
"parse_errors": 0,
|
||
"sent_this_run": 0,
|
||
"skipped_due_to_limit": 0
|
||
}
|
||
|
||
processed_count = 0
|
||
|
||
print(f"Traitement de {len(events)} événements")
|
||
if self.max_events:
|
||
print(f"Limite d'événements: {self.max_events}")
|
||
if self.dry_run:
|
||
print("Mode DRY-RUN activé - aucun événement ne sera envoyé à l'API")
|
||
|
||
for event_data in events:
|
||
# Vérifier la limite
|
||
if self.max_events and processed_count >= self.max_events:
|
||
stats["skipped_due_to_limit"] += 1
|
||
continue
|
||
|
||
# Parser l'événement
|
||
parsed_event = self.parse_event(event_data)
|
||
event_id = parsed_event["id"]
|
||
|
||
# Vérifier si déjà traité
|
||
if event_id in self.cache_data["processed_events"]:
|
||
stats["already_saved"] += 1
|
||
print(f"Événement déjà traité: {parsed_event['event']['properties']['label']}")
|
||
continue
|
||
|
||
# Vérifier si l'événement a déjà été traité avec succès
|
||
skip_geocoding = False
|
||
if event_id in self.events_data["events"]:
|
||
event_status = self.events_data["events"][event_id].get("status", "unknown")
|
||
if event_status in ["saved", "already_exists"]:
|
||
skip_geocoding = True
|
||
print(f"ℹ️ Géocodage ignoré pour {parsed_event['event']['properties']['label']} - déjà traité")
|
||
|
||
# Envoyer à l'API
|
||
success, message = self.send_event_to_api(parsed_event, skip_geocoding=skip_geocoding)
|
||
|
||
if success:
|
||
stats["new_events"] += 1
|
||
stats["sent_this_run"] += 1
|
||
|
||
# Mettre à jour les données
|
||
self.events_data["events"][event_id] = {
|
||
"status": "saved",
|
||
"message": message,
|
||
"last_attempt": datetime.now().isoformat(),
|
||
"event": parsed_event["event"]
|
||
}
|
||
|
||
self.cache_data["processed_events"][event_id] = {
|
||
"processed_at": datetime.now().isoformat(),
|
||
"status": "saved",
|
||
"event_label": parsed_event["event"]["properties"]["label"]
|
||
}
|
||
|
||
print(f"✅ {parsed_event['event']['properties']['label']} - {message}")
|
||
else:
|
||
stats["api_errors"] += 1
|
||
print(f"❌ {parsed_event['event']['properties']['label']} - Erreur")
|
||
|
||
processed_count += 1
|
||
|
||
# Mettre à jour les timestamps
|
||
self.events_data["last_update"] = datetime.now().isoformat()
|
||
self.cache_data["last_fetch"] = datetime.now().isoformat()
|
||
|
||
# Sauvegarder
|
||
self.save_events_data()
|
||
self.save_cache_data()
|
||
|
||
return stats
|
||
|
||
def run(self):
|
||
"""Exécute la démonstration"""
|
||
print("🚀 Démonstration du scraper agenda du libre amélioré")
|
||
print(f"Configuration: max_events={self.max_events}, dry_run={self.dry_run}")
|
||
print("=" * 60)
|
||
|
||
# Simuler la récupération iCal
|
||
ical_content = self.simulate_ical_fetch()
|
||
content_hash = self.get_content_hash(ical_content)
|
||
|
||
# Vérifier si le contenu a changé
|
||
if self.cache_data["content_hash"] == content_hash:
|
||
print("Contenu iCal identique au précédent, utilisation du cache")
|
||
else:
|
||
print("Nouveau contenu iCal détecté, mise à jour du cache")
|
||
self.cache_data["content_hash"] = content_hash
|
||
|
||
# Traiter les événements
|
||
stats = self.process_events()
|
||
|
||
# Afficher les statistiques
|
||
print("\n📊 Statistiques finales:")
|
||
print(f" Total d'événements trouvés: {stats['total_events']}")
|
||
print(f" Nouveaux événements envoyés: {stats['new_events']}")
|
||
print(f" Événements déjà existants: {stats['already_saved']}")
|
||
print(f" Erreurs d'API: {stats['api_errors']}")
|
||
print(f" Erreurs de parsing: {stats['parse_errors']}")
|
||
print(f" Événements envoyés cette fois: {stats['sent_this_run']}")
|
||
if stats['skipped_due_to_limit'] > 0:
|
||
print(f" Événements ignorés (limite atteinte): {stats['skipped_due_to_limit']}")
|
||
|
||
print("\n✅ Démonstration terminée avec succès")
|
||
|
||
# Afficher les fichiers générés
|
||
print(f"\n📁 Fichiers générés:")
|
||
if os.path.exists(self.cache_file):
|
||
print(f" Cache: {self.cache_file}")
|
||
if os.path.exists(self.events_file):
|
||
print(f" Événements: {self.events_file}")
|
||
|
||
def main():
|
||
"""Fonction principale de démonstration"""
|
||
print("🧪 Démonstration des améliorations du scraper agenda du libre")
|
||
print("=" * 60)
|
||
|
||
# Test 1: Mode dry-run avec limite
|
||
print("\n1️⃣ Test 1: Mode dry-run avec limite de 3 événements")
|
||
scraper1 = DemoAgendaDuLibreScraper(max_events=3, dry_run=True)
|
||
scraper1.run()
|
||
|
||
# Test 2: Mode dry-run sans limite
|
||
print("\n2️⃣ Test 2: Mode dry-run sans limite")
|
||
scraper2 = DemoAgendaDuLibreScraper(max_events=None, dry_run=True)
|
||
scraper2.run()
|
||
|
||
# Test 3: Mode réel avec limite
|
||
print("\n3️⃣ Test 3: Mode réel avec limite de 2 événements")
|
||
scraper3 = DemoAgendaDuLibreScraper(max_events=2, dry_run=False)
|
||
scraper3.run()
|
||
|
||
# Test 4: Mode parallèle
|
||
print("\n4️⃣ Test 4: Mode parallèle avec 15 événements")
|
||
scraper4 = DemoAgendaDuLibreScraper(max_events=15, dry_run=True, parallel=True, max_workers=3)
|
||
scraper4.run()
|
||
|
||
print("\n🎉 Toutes les démonstrations sont terminées !")
|
||
print("\nFonctionnalités démontrées:")
|
||
print("✅ Cache JSON intelligent")
|
||
print("✅ Limitation du nombre d'événements")
|
||
print("✅ Mode dry-run par défaut")
|
||
print("✅ Détection de changements de contenu")
|
||
print("✅ Suivi des événements traités")
|
||
print("✅ Traitement parallèle")
|
||
|
||
if __name__ == "__main__":
|
||
main()
|