Remove unreferenced legacy generators, updater, and analysis scripts

The graphify code-graph pass confirmed nothing in the active pipeline
(scripts/automation/, shell entrypoints) imports or calls any of
these - only scripts/generators/ultimate_ai_ml_eurojackpot_generator.py
is wired into automation. Removes:

- ultimate_ai_ml_eurojackpot_generator_v2.1_backup.py, a verbatim
  duplicate of the active generator's classes (UltimateAIMLEurojackpot-
  Generator, EurojackpotAIMLEngine, PatternEngine, HybridOptimizer)
- optimized_eurojackpot_generator.py, a third standalone generator
  documented in README but never imported
- update_historical_data.py, a second data updater never imported
- 12 standalone analysis/utility scripts (bereichsanalyse, positions-
  analyse, NMMHH generators, processors, etc.) with no automation ties

History is preserved in git if anything here turns out to still be
wanted. README still documents most of these - follow-up needed there.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
cbazzaandClaude Sonnet 5 committed 2026-08-10 18:53:39 +02:00
1 parent 5703e6a12c
commit f23922e05e
16 files changed
-5105

No files matched your search

-77
View File
@@ -1,77 +0,0 @@
#!/usr/bin/env python3
"""
Erstellt Beispiel-CSV-Dateien für das Eurojackpot-Processing
"""
import pandas as pd
import itertools
from datetime import datetime, timedelta
import random
def create_all_combinations():
"""Erstellt eine CSV mit allen möglichen 5-aus-50 Kombinationen (Beispiel mit ersten 100)."""
print("Erstelle Beispiel-Kombinationsdatei...")
# Für Demo: nur erste 100 Kombinationen von 5 aus 20 Zahlen
# (Vollständige 5-aus-50 Kombinationen wären über 2 Millionen!)
combinations = []
count = 0
for combo in itertools.combinations(range(1, 21), 5): # 5 aus 20 für Demo
combinations.append({
'Zahl1': combo[0],
'Zahl2': combo[1],
'Zahl3': combo[2],
'Zahl4': combo[3],
'Zahl5': combo[4]
})
count += 1
if count >= 100: # Limitierung für Demo
break
df = pd.DataFrame(combinations)
df.to_csv('alle_kombinationen_beispiel.csv', index=False)
print(f"Beispiel-Kombinationsdatei erstellt: {len(df)} Kombinationen")
return df
def create_drawn_numbers():
"""Erstellt eine CSV mit gezogenen Zahlen (Beispieldaten)."""
print("Erstelle Beispiel-Datei mit gezogenen Zahlen...")
drawn_numbers = []
start_date = datetime(2023, 1, 1)
# 20 zufällige Ziehungen erstellen
for i in range(20):
date = start_date + timedelta(days=i*7) # Wöchentliche Ziehungen
# 5 zufällige Zahlen zwischen 1 und 20 (ohne Wiederholung)
numbers = sorted(random.sample(range(1, 21), 5))
drawn_numbers.append({
'Datum': date.strftime('%Y-%m-%d'),
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4]
})
df = pd.DataFrame(drawn_numbers)
df.to_csv('gezogene_zahlen_beispiel.csv', index=False)
print(f"Beispiel-Datei mit gezogenen Zahlen erstellt: {len(df)} Ziehungen")
return df
if __name__ == "__main__":
print("=== Erstelle Beispiel-CSV-Dateien ===\n")
# Seed für reproduzierbare Ergebnisse
random.seed(42)
combinations_df = create_all_combinations()
drawn_df = create_drawn_numbers()
print("\n=== Beispieldateien erstellt ===")
print("- alle_kombinationen_beispiel.csv")
print("- gezogene_zahlen_beispiel.csv")
print("\nSie können jetzt das Hauptscript testen:")
-165
View File
@@ -1,165 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot CSV Processor
Dieses Script liest zwei CSV-Dateien ein:
1. Alle möglichen Zahlenkombinationen (5 Zahlen)
2. Bereits gezogene Zahlen mit Datumsstempel
Es markiert in der ersten Datei alle bereits gezogenen Kombinationen mit 1 (sonst 0).
"""
import pandas as pd
import sys
from pathlib import Path
def load_combinations_file(filepath):
"""Lädt die Datei mit allen möglichen Kombinationen."""
try:
df = pd.read_csv(filepath)
print(f"Kombinationen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der Kombinationsdatei: {e}")
return None
def load_drawn_numbers_file(filepath):
"""Lädt die Datei mit bereits gezogenen Zahlen."""
try:
df = pd.read_csv(filepath)
print(f"Gezogene Zahlen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der gezogenen Zahlen: {e}")
return None
def create_combination_key(row, z_columns):
"""Erstellt einen eindeutigen Schlüssel aus den 5 Zahlen (sortiert)."""
numbers = [row[col] for col in z_columns]
return tuple(sorted(numbers))
def process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file):
"""Hauptfunktion zur Verarbeitung der Eurojackpot-Daten."""
# CSV-Dateien laden
print("Lade Kombinationsdatei...")
combinations_df = load_combinations_file(combinations_file)
if combinations_df is None:
return False
print("\nLade Datei mit gezogenen Zahlen...")
drawn_df = load_drawn_numbers_file(drawn_numbers_file)
if drawn_df is None:
return False
# Spalten für Zahlen identifizieren
# Annahme: In der Kombinationsdatei sind die ersten 5 Spalten die Zahlen
# In der gezogenen Zahlen-Datei sind es Z1, Z2, Z3, Z4, Z5
# Für Kombinationsdatei - erste 5 numerische Spalten verwenden
numeric_cols = combinations_df.select_dtypes(include=['number']).columns
if len(numeric_cols) >= 5:
combo_z_columns = numeric_cols[:5].tolist()
else:
# Fallback: erste 5 Spalten nehmen
combo_z_columns = combinations_df.columns[:5].tolist()
print(f"Verwendete Spalten für Kombinationen: {combo_z_columns}")
# Für gezogene Zahlen - Z1 bis Z5 Spalten suchen
z_columns = [col for col in drawn_df.columns if col.startswith('Z') and col[1:].isdigit()]
z_columns = sorted(z_columns)[:5] # Ersten 5 Z-Spalten nehmen
if not z_columns:
# Fallback: nach Spalten mit "Zahl" im Namen suchen oder numerische Spalten
z_columns = [col for col in drawn_df.columns if 'zahl' in col.lower()][:5]
if not z_columns:
z_columns = drawn_df.select_dtypes(include=['number']).columns[:5].tolist()
print(f"Verwendete Spalten für gezogene Zahlen: {z_columns}")
# Set mit allen gezogenen Kombinationen erstellen
print("\nErstelle Set mit gezogenen Kombinationen...")
drawn_combinations = set()
for _, row in drawn_df.iterrows():
combo_key = create_combination_key(row, z_columns)
drawn_combinations.add(combo_key)
print(f"Anzahl eindeutige gezogene Kombinationen: {len(drawn_combinations)}")
# Neue Spalte für Markierungen hinzufügen
print("\nMarkiere gezogene Kombinationen...")
combinations_df['bereits_gezogen'] = 0
marked_count = 0
for idx, row in combinations_df.iterrows():
combo_key = create_combination_key(row, combo_z_columns)
if combo_key in drawn_combinations:
combinations_df.at[idx, 'bereits_gezogen'] = 1
marked_count += 1
print(f"Anzahl markierte Kombinationen: {marked_count}")
# Ergebnis speichern
print(f"\nSpeichere Ergebnis in: {output_file}")
combinations_df.to_csv(output_file, index=False)
# Statistiken ausgeben
total_combinations = len(combinations_df)
drawn_percentage = (marked_count / total_combinations) * 100 if total_combinations > 0 else 0
print(f"\n=== STATISTIKEN ===")
print(f"Gesamte Kombinationen: {total_combinations:,}")
print(f"Bereits gezogene Kombinationen: {marked_count:,}")
print(f"Prozentsatz bereits gezogen: {drawn_percentage:.4f}%")
print(f"Noch nicht gezogene Kombinationen: {total_combinations - marked_count:,}")
return True
def main():
"""Hauptfunktion mit Benutzerinteraktion."""
print("=== Eurojackpot CSV Processor ===\n")
# Dateipfade abfragen oder Standard verwenden
if len(sys.argv) >= 4:
combinations_file = sys.argv[1]
drawn_numbers_file = sys.argv[2]
output_file = sys.argv[3]
else:
print("Geben Sie die Dateipfade ein (oder drücken Sie Enter für Standard):")
combinations_file = input("Pfad zur Kombinationsdatei (alle_kombinationen.csv): ").strip()
if not combinations_file:
combinations_file = "alle_kombinationen.csv"
drawn_numbers_file = input("Pfad zur Datei mit gezogenen Zahlen (gezogene_zahlen.csv): ").strip()
if not drawn_numbers_file:
drawn_numbers_file = "gezogene_zahlen.csv"
output_file = input("Pfad für Ausgabedatei (kombinationen_markiert.csv): ").strip()
if not output_file:
output_file = "kombinationen_markiert.csv"
# Überprüfen ob Dateien existieren
if not Path(combinations_file).exists():
print(f"Fehler: Kombinationsdatei '{combinations_file}' nicht gefunden!")
return
if not Path(drawn_numbers_file).exists():
print(f"Fehler: Datei mit gezogenen Zahlen '{drawn_numbers_file}' nicht gefunden!")
return
# Verarbeitung starten
success = process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file)
if success:
print(f"\n✅ Verarbeitung erfolgreich abgeschlossen!")
print(f"Ergebnis gespeichert in: {output_file}")
else:
print("\n❌ Fehler bei der Verarbeitung!")
if __name__ == "__main__":
main()
@@ -1,220 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot CSV Processor - Angepasst für Semikolon-getrennte CSV-Dateien
Dieses Script liest zwei CSV-Dateien ein:
1. Alle möglichen Zahlenkombinationen (5 Zahlen)
2. Bereits gezogene Zahlen mit Datumsstempel
Es markiert in der ersten Datei alle bereits gezogenen Kombinationen mit 1 (sonst 0).
"""
import pandas as pd
import sys
from pathlib import Path
def detect_separator(filepath):
"""Erkennt das CSV-Trennzeichen automatisch."""
try:
with open(filepath, 'r', encoding='utf-8') as f:
first_line = f.readline()
if ';' in first_line and first_line.count(';') > first_line.count(','):
return ';'
return ','
except:
return ','
def load_combinations_file(filepath):
"""Lädt die Datei mit allen möglichen Kombinationen."""
try:
sep = detect_separator(filepath)
print(f"Erkanntes Trennzeichen für Kombinationen: '{sep}'")
df = pd.read_csv(filepath, sep=sep)
print(f"Kombinationen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der Kombinationsdatei: {e}")
return None
def load_drawn_numbers_file(filepath):
"""Lädt die Datei mit bereits gezogenen Zahlen."""
try:
sep = detect_separator(filepath)
print(f"Erkanntes Trennzeichen für gezogene Zahlen: '{sep}'")
df = pd.read_csv(filepath, sep=sep)
print(f"Gezogene Zahlen geladen: {len(df)} Zeilen")
print(f"Spalten: {list(df.columns)}")
return df
except Exception as e:
print(f"Fehler beim Laden der gezogenen Zahlen: {e}")
return None
def identify_number_columns(df, is_combinations=True):
"""Identifiziert die Spalten mit den Zahlen."""
columns = df.columns.tolist()
if is_combinations:
# Für Kombinationsdatei: Z1, Z2, Z3, Z4, Z5 suchen
z_cols = [col for col in columns if col.startswith('Z') and len(col) == 2 and col[1:].isdigit()]
z_cols = sorted(z_cols)[:5]
if len(z_cols) >= 5:
return z_cols
# Fallback: erste 5 numerische Spalten
numeric_cols = df.select_dtypes(include=['number']).columns[:5].tolist()
if len(numeric_cols) >= 5:
return numeric_cols
# Fallback: erste 5 Spalten
return columns[:5]
else:
# Für gezogene Zahlen: Z1-Z5 suchen (nicht SZ1, SZ2)
z_cols = [col for col in columns if col.startswith('Z') and len(col) == 2 and col[1:].isdigit()]
z_cols = [col for col in z_cols if not col.startswith('SZ')] # Superzahlen ausschließen
z_cols = sorted(z_cols)[:5]
if len(z_cols) >= 5:
return z_cols
# Fallback: numerische Spalten (ohne Datum)
numeric_cols = df.select_dtypes(include=['number']).columns
numeric_cols = [col for col in numeric_cols if 'datum' not in col.lower()][:5]
if len(numeric_cols) >= 5:
return numeric_cols.tolist()
# Letzter Fallback
return columns[:5]
def create_combination_key(row, z_columns):
"""Erstellt einen eindeutigen Schlüssel aus den 5 Zahlen (sortiert)."""
try:
numbers = [int(row[col]) for col in z_columns]
return tuple(sorted(numbers))
except:
return None
def process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file):
"""Hauptfunktion zur Verarbeitung der Eurojackpot-Daten."""
# CSV-Dateien laden
print("Lade Kombinationsdatei...")
combinations_df = load_combinations_file(combinations_file)
if combinations_df is None:
return False
print("\nLade Datei mit gezogenen Zahlen...")
drawn_df = load_drawn_numbers_file(drawn_numbers_file)
if drawn_df is None:
return False
# Spalten für Zahlen identifizieren
combo_z_columns = identify_number_columns(combinations_df, is_combinations=True)
drawn_z_columns = identify_number_columns(drawn_df, is_combinations=False)
print(f"\nVerwendete Spalten für Kombinationen: {combo_z_columns}")
print(f"Verwendete Spalten für gezogene Zahlen: {drawn_z_columns}")
# Datencheck
print(f"\nErste Kombination: {combinations_df[combo_z_columns].iloc[0].tolist()}")
print(f"Erste gezogene Zahlen: {drawn_df[drawn_z_columns].iloc[0].tolist()}")
# Set mit allen gezogenen Kombinationen erstellen
print("\nErstelle Set mit gezogenen Kombinationen...")
drawn_combinations = set()
for _, row in drawn_df.iterrows():
combo_key = create_combination_key(row, drawn_z_columns)
if combo_key:
drawn_combinations.add(combo_key)
print(f"Anzahl eindeutige gezogene Kombinationen: {len(drawn_combinations)}")
# Beispiele anzeigen
if drawn_combinations:
print(f"Erste 5 gezogene Kombinationen: {list(drawn_combinations)[:5]}")
# Neue Spalte für Markierungen hinzufügen (falls noch nicht vorhanden)
if 'bereits_gezogen' not in combinations_df.columns:
combinations_df['bereits_gezogen'] = 0
else:
combinations_df['bereits_gezogen'] = 0 # Zurücksetzen
print("\nMarkiere gezogene Kombinationen...")
marked_count = 0
for idx, row in combinations_df.iterrows():
combo_key = create_combination_key(row, combo_z_columns)
if combo_key and combo_key in drawn_combinations:
combinations_df.at[idx, 'bereits_gezogen'] = 1
marked_count += 1
if marked_count <= 5: # Erste 5 Treffer anzeigen
print(f"Treffer gefunden: {combo_key}")
print(f"Anzahl markierte Kombinationen: {marked_count}")
# Ergebnis speichern
print(f"\nSpeichere Ergebnis in: {output_file}")
sep = detect_separator(combinations_file) # Gleiches Trennzeichen wie Eingabe verwenden
combinations_df.to_csv(output_file, sep=sep, index=False)
# Statistiken ausgeben
total_combinations = len(combinations_df)
drawn_percentage = (marked_count / total_combinations) * 100 if total_combinations > 0 else 0
print(f"\n=== STATISTIKEN ===")
print(f"Gesamte Kombinationen: {total_combinations:,}")
print(f"Bereits gezogene Kombinationen: {marked_count:,}")
print(f"Prozentsatz bereits gezogen: {drawn_percentage:.4f}%")
print(f"Noch nicht gezogene Kombinationen: {total_combinations - marked_count:,}")
return True
def main():
"""Hauptfunktion mit Benutzerinteraktion."""
print("=== Eurojackpot CSV Processor (Fixed) ===\n")
# Dateipfade abfragen oder Standard verwenden
if len(sys.argv) >= 4:
combinations_file = sys.argv[1]
drawn_numbers_file = sys.argv[2]
output_file = sys.argv[3]
else:
print("Geben Sie die Dateipfade ein (oder drücken Sie Enter für Standard):")
combinations_file = input("Pfad zur Kombinationsdatei: ").strip()
if not combinations_file:
combinations_file = "Alle_Eurojackpot_Kombinationen_mit_Status.csv"
drawn_numbers_file = input("Pfad zur Datei mit gezogenen Zahlen: ").strip()
if not drawn_numbers_file:
drawn_numbers_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
output_file = input("Pfad für Ausgabedatei: ").strip()
if not output_file:
output_file = "Kombinationen_markiert_fixed.csv"
# Überprüfen ob Dateien existieren
if not Path(combinations_file).exists():
print(f"Fehler: Kombinationsdatei '{combinations_file}' nicht gefunden!")
return
if not Path(drawn_numbers_file).exists():
print(f"Fehler: Datei mit gezogenen Zahlen '{drawn_numbers_file}' nicht gefunden!")
return
# Verarbeitung starten
success = process_eurojackpot_data(combinations_file, drawn_numbers_file, output_file)
if success:
print(f"\n✅ Verarbeitung erfolgreich abgeschlossen!")
print(f"Ergebnis gespeichert in: {output_file}")
else:
print("\n❌ Fehler bei der Verarbeitung!")
if __name__ == "__main__":
main()
-62
View File
@@ -1,62 +0,0 @@
#!/usr/bin/env python3
"""
Vereinfachte Version des Eurojackpot Processors
Für spezifische Spaltenstrukturen
"""
import pandas as pd
def process_eurojackpot_simple(combinations_csv, drawn_numbers_csv, output_csv):
"""
Vereinfachte Verarbeitung mit festen Spaltenstrukturen
Parameter:
- combinations_csv: CSV mit allen Kombinationen (Spalten: Zahl1, Zahl2, Zahl3, Zahl4, Zahl5)
- drawn_numbers_csv: CSV mit gezogenen Zahlen (Spalten: Datum, Z1, Z2, Z3, Z4, Z5)
- output_csv: Ausgabedatei
"""
# Dateien laden
print("Lade Kombinationsdatei...")
combinations = pd.read_csv(combinations_csv)
print("Lade gezogene Zahlen...")
drawn = pd.read_csv(drawn_numbers_csv)
# Gezogene Kombinationen als Set erstellen (sortiert für Vergleich)
drawn_sets = set()
for _, row in drawn.iterrows():
# Annahme: Spalten Z1, Z2, Z3, Z4, Z5 enthalten die Zahlen
numbers = sorted([row['Z1'], row['Z2'], row['Z3'], row['Z4'], row['Z5']])
drawn_sets.add(tuple(numbers))
print(f"Gefundene gezogene Kombinationen: {len(drawn_sets)}")
# Neue Spalte hinzufügen
combinations['bereits_gezogen'] = 0
# Jede Kombination prüfen
marked = 0
for idx, row in combinations.iterrows():
# Annahme: erste 5 Spalten enthalten die Zahlenkombination
combo_cols = combinations.columns[:5]
numbers = sorted([row[col] for col in combo_cols])
if tuple(numbers) in drawn_sets:
combinations.at[idx, 'bereits_gezogen'] = 1
marked += 1
# Ergebnis speichern
combinations.to_csv(output_csv, index=False)
print(f"Verarbeitung abgeschlossen!")
print(f"Markierte Kombinationen: {marked}")
print(f"Ergebnis gespeichert in: {output_csv}")
# Beispielaufruf
if __name__ == "__main__":
process_eurojackpot_simple(
"alle_kombinationen.csv",
"gezogene_zahlen.csv",
"kombinationen_markiert.csv"
)
-681
View File
@@ -1,681 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Historical Data Updater
Lädt automatisch die neuesten Eurojackpot-Ziehungen von der offiziellen Website
und aktualisiert die lokale CSV-Datei.
Quellen:
- https://www.eurojackpot.de/de/eurojackpot/gewinnzahlen.html
- Oder alternative APIs/Websites
Features:
- Automatisches Scraping der neuesten Ziehungen
- Duplikate-Vermeidung
- Backup vor Update
- Validierung der neuen Daten
"""
import pandas as pd
import requests
from bs4 import BeautifulSoup
from datetime import datetime
import shutil
import os
import re
from typing import List, Dict, Optional
import time
class EurojackpotDataUpdater:
"""Aktualisiert historische Eurojackpot-Daten automatisch."""
def __init__(self, data_file: str):
"""
Initialisiert den Updater.
Args:
data_file: Pfad zur lokalen CSV-Datei
"""
self.data_file = data_file
self.backup_file = None
self.df_existing = None
# API/Scraping URLs
self.sources = {
'eurojackpot_de': 'https://www.eurojackpot.de/de/eurojackpot/gewinnzahlen.html',
'euro-jackpot_net': 'https://www.euro-jackpot.net/de/gewinnzahlen',
'lottode': 'https://www.lotto.de/eurojackpot/gewinnzahlen'
}
print("🔄 EUROJACKPOT DATA UPDATER")
print("=" * 60)
def load_existing_data(self) -> bool:
"""Lädt existierende Daten."""
try:
if not os.path.exists(self.data_file):
print(f"⚠️ Datei nicht gefunden: {self.data_file}")
print(" Erstelle neue Datei...")
self.df_existing = pd.DataFrame(columns=['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'SZ1', 'SZ2'])
return True
self.df_existing = pd.read_csv(self.data_file, sep=';')
# Datum als datetime
if 'datum' in self.df_existing.columns:
self.df_existing['datum'] = pd.to_datetime(
self.df_existing['datum'],
format='%Y-%m-%d',
errors='coerce'
)
print(f"✅ Existierende Daten geladen: {len(self.df_existing)} Ziehungen")
if len(self.df_existing) > 0:
latest = self.df_existing['datum'].max()
print(f" Neueste Ziehung: {latest.strftime('%Y-%m-%d') if pd.notna(latest) else 'Unbekannt'}")
return True
except Exception as e:
print(f"❌ Fehler beim Laden: {e}")
return False
def create_backup(self) -> bool:
"""Erstellt Backup der existierenden Datei."""
if not os.path.exists(self.data_file):
return True
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_dir = os.path.join(os.path.dirname(self.data_file), "backups")
os.makedirs(backup_dir, exist_ok=True)
filename = os.path.basename(self.data_file)
self.backup_file = os.path.join(backup_dir, f"{filename}.backup_{timestamp}")
shutil.copy2(self.data_file, self.backup_file)
print(f"✅ Backup erstellt: {os.path.basename(self.backup_file)}")
return True
except Exception as e:
print(f"⚠️ Backup-Fehler: {e}")
return False
def fetch_from_eurojackpot_de(self) -> List[Dict]:
"""
Scrapt Daten von eurojackpot.de
Returns:
Liste von Ziehungen als Dictionaries
"""
print("\n🌐 Versuche eurojackpot.de...")
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
}
response = requests.get(self.sources['eurojackpot_de'], headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
# Suche nach Ziehungsergebnissen
# Dies ist ein generisches Beispiel - muss an tatsächliche Website-Struktur angepasst werden
draws = []
# Beispiel-Parsing (muss angepasst werden!)
result_blocks = soup.find_all('div', class_='drawing-result')
for block in result_blocks[:10]: # Letzte 10 Ziehungen
try:
# Datum extrahieren
date_elem = block.find('span', class_='date')
if not date_elem:
continue
date_str = date_elem.text.strip()
date_obj = self._parse_german_date(date_str)
# Zahlen extrahieren
numbers = []
number_elems = block.find_all('span', class_='ball')
for num_elem in number_elems[:5]:
num = int(num_elem.text.strip())
numbers.append(num)
# Eurozahlen extrahieren
euro_numbers = []
euro_elems = block.find_all('span', class_='euro-ball')
for euro_elem in euro_elems[:2]:
euro_num = int(euro_elem.text.strip())
euro_numbers.append(euro_num)
if len(numbers) == 5 and len(euro_numbers) == 2:
draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'SZ1': euro_numbers[0],
'SZ2': euro_numbers[1]
})
except Exception as e:
continue
if draws:
print(f" ✅ {len(draws)} Ziehungen gefunden")
return draws
else:
print(" ⚠️ Keine Ziehungen gefunden (HTML-Struktur möglicherweise geändert)")
return []
except Exception as e:
print(f" ❌ Fehler: {e}")
return []
def fetch_from_euro_jackpot_net(self) -> List[Dict]:
"""
Scrapt Daten von euro-jackpot.net
Returns:
Liste von Ziehungen
"""
print("\n🌐 Versuche euro-jackpot.net...")
try:
headers = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36'
}
response = requests.get(self.sources['euro-jackpot_net'], headers=headers, timeout=10)
response.raise_for_status()
soup = BeautifulSoup(response.content, 'html.parser')
draws = []
# Parsing-Logik für diese Website
# (Platzhalter - muss an tatsächliche Struktur angepasst werden)
result_rows = soup.find_all('tr', class_='result-row')
for row in result_rows[:10]:
try:
cells = row.find_all('td')
if len(cells) < 8:
continue
# Datum
date_str = cells[0].text.strip()
date_obj = self._parse_german_date(date_str)
# Hauptzahlen
numbers = [int(cells[i].text.strip()) for i in range(1, 6)]
# Eurozahlen
euro_numbers = [int(cells[i].text.strip()) for i in range(6, 8)]
draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'SZ1': euro_numbers[0],
'SZ2': euro_numbers[1]
})
except Exception as e:
continue
if draws:
print(f" ✅ {len(draws)} Ziehungen gefunden")
else:
print(" ⚠️ Keine Ziehungen gefunden")
return draws
except Exception as e:
print(f" ❌ Fehler: {e}")
return []
def fetch_from_manual_input(self) -> List[Dict]:
"""
Manuelle Eingabe von neuen Ziehungen.
Returns:
Liste von Ziehungen
"""
print("\n⌨️ MANUELLE EINGABE")
print("=" * 60)
print("Gib die neuesten Ziehungen manuell ein.")
print("Format: YYYY-MM-DD Z1 Z2 Z3 Z4 Z5 SZ1 SZ2")
print("Beispiel: 2025-01-24 7 18 26 37 46 3 11")
print("Leer lassen zum Beenden.\n")
draws = []
while True:
user_input = input(f"Ziehung {len(draws) + 1}: ").strip()
if not user_input:
break
try:
parts = user_input.split()
if len(parts) != 8:
print(" ❌ Ungültiges Format. Bitte 8 Werte eingeben.")
continue
date_obj = datetime.strptime(parts[0], '%Y-%m-%d')
numbers = [int(parts[i]) for i in range(1, 6)]
euro_numbers = [int(parts[i]) for i in range(6, 8)]
# Validierung
if not all(1 <= n <= 50 for n in numbers):
print(" ❌ Hauptzahlen müssen zwischen 1 und 50 liegen.")
continue
if not all(1 <= n <= 12 for n in euro_numbers):
print(" ❌ Eurozahlen müssen zwischen 1 und 12 liegen.")
continue
if len(set(numbers)) != 5:
print(" ❌ Hauptzahlen müssen eindeutig sein.")
continue
if len(set(euro_numbers)) != 2:
print(" ❌ Eurozahlen müssen eindeutig sein.")
continue
draws.append({
'datum': date_obj,
'Z1': numbers[0],
'Z2': numbers[1],
'Z3': numbers[2],
'Z4': numbers[3],
'Z5': numbers[4],
'SZ1': euro_numbers[0],
'SZ2': euro_numbers[1]
})
print(f" ✅ Ziehung hinzugefügt: {date_obj.strftime('%Y-%m-%d')}")
except ValueError as e:
print(f" ❌ Fehler: {e}")
continue
if draws:
print(f"\n✅ {len(draws)} Ziehungen manuell eingegeben")
return draws
def _parse_german_date(self, date_str: str) -> datetime:
"""
Parst deutsches Datumsformat.
Args:
date_str: Datum als String (z.B. "24.01.2025" oder "24. Januar 2025")
Returns:
datetime Objekt
"""
# Entferne zusätzliche Leerzeichen
date_str = re.sub(r'\s+', ' ', date_str.strip())
# Monatsnamen-Mapping
months_de = {
'januar': 1, 'februar': 2, 'märz': 3, 'april': 4,
'mai': 5, 'juni': 6, 'juli': 7, 'august': 8,
'september': 9, 'oktober': 10, 'november': 11, 'dezember': 12
}
# Versuche verschiedene Formate
formats = [
'%d.%m.%Y',
'%d.%m.%y',
'%Y-%m-%d',
'%d/%m/%Y'
]
for fmt in formats:
try:
return datetime.strptime(date_str, fmt)
except ValueError:
continue
# Versuche mit Monatsnamen
for month_name, month_num in months_de.items():
if month_name.lower() in date_str.lower():
# Extrahiere Tag und Jahr
match = re.search(r'(\d{1,2})\.?\s+' + month_name + r'\s+(\d{4})', date_str, re.IGNORECASE)
if match:
day = int(match.group(1))
year = int(match.group(2))
return datetime(year, month_num, day)
# Fallback: aktuelles Datum
print(f" ⚠️ Konnte Datum nicht parsen: {date_str}, nutze aktuelles Datum")
return datetime.now()
def fetch_new_draws(self, source: str = 'auto') -> List[Dict]:
"""
Holt neue Ziehungen von der gewählten Quelle.
Args:
source: 'auto', 'eurojackpot_de', 'euro_jackpot_net', 'manual'
Returns:
Liste von neuen Ziehungen
"""
print(f"\n🔍 SUCHE NACH NEUEN ZIEHUNGEN (Quelle: {source})")
print("=" * 60)
all_draws = []
if source == 'auto':
# Versuche alle Quellen
sources_to_try = [
('eurojackpot_de', self.fetch_from_eurojackpot_de),
('euro_jackpot_net', self.fetch_from_euro_jackpot_net)
]
for source_name, fetch_func in sources_to_try:
draws = fetch_func()
if draws:
all_draws.extend(draws)
break # Erste erfolgreiche Quelle nutzen
time.sleep(1) # Pause zwischen Requests
if not all_draws:
print("\n⚠️ Automatisches Scraping fehlgeschlagen.")
print(" Möchtest du Daten manuell eingeben? (j/n): ", end='')
if input().lower() in ['j', 'ja', 'y', 'yes']:
all_draws = self.fetch_from_manual_input()
elif source == 'eurojackpot_de':
all_draws = self.fetch_from_eurojackpot_de()
elif source == 'euro_jackpot_net':
all_draws = self.fetch_from_euro_jackpot_net()
elif source == 'manual':
all_draws = self.fetch_from_manual_input()
else:
print(f"❌ Unbekannte Quelle: {source}")
return all_draws
def validate_draw(self, draw: Dict) -> bool:
"""
Validiert eine Ziehung.
Args:
draw: Ziehungs-Dictionary
Returns:
True wenn valide
"""
try:
# Prüfe Pflichtfelder
required_fields = ['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'SZ1', 'SZ2']
if not all(field in draw for field in required_fields):
return False
# Prüfe Hauptzahlen (1-50)
main_numbers = [draw[f'Z{i}'] for i in range(1, 6)]
if not all(1 <= n <= 50 for n in main_numbers):
return False
if len(set(main_numbers)) != 5: # Eindeutig
return False
# Prüfe Eurozahlen (1-12)
euro_numbers = [draw['SZ1'], draw['SZ2']]
if not all(1 <= n <= 12 for n in euro_numbers):
return False
if len(set(euro_numbers)) != 2: # Eindeutig
return False
# Prüfe Datum
if not isinstance(draw['datum'], datetime):
return False
return True
except Exception:
return False
def merge_with_existing(self, new_draws: List[Dict]) -> pd.DataFrame:
"""
Merged neue Ziehungen mit existierenden Daten.
Args:
new_draws: Liste von neuen Ziehungen
Returns:
Zusammengeführter DataFrame
"""
print(f"\n🔀 MERGE MIT EXISTIERENDEN DATEN")
print("=" * 60)
# Validiere neue Ziehungen
valid_draws = [draw for draw in new_draws if self.validate_draw(draw)]
if len(valid_draws) < len(new_draws):
invalid_count = len(new_draws) - len(valid_draws)
print(f"⚠️ {invalid_count} ungültige Ziehung(en) übersprungen")
if not valid_draws:
print("❌ Keine gültigen neuen Ziehungen zum Hinzufügen")
return self.df_existing
# Erstelle DataFrame aus neuen Ziehungen
df_new = pd.DataFrame(valid_draws)
# Kombiniere
if self.df_existing is None or len(self.df_existing) == 0:
df_combined = df_new
else:
df_combined = pd.concat([self.df_existing, df_new], ignore_index=True)
# Entferne Duplikate (basierend auf Datum + Zahlen)
before_dedup = len(df_combined)
df_combined = df_combined.drop_duplicates(
subset=['datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5'],
keep='first'
)
after_dedup = len(df_combined)
duplicates_removed = before_dedup - after_dedup
if duplicates_removed > 0:
print(f"🗑️ {duplicates_removed} Duplikat(e) entfernt")
# Sortiere nach Datum
df_combined = df_combined.sort_values('datum', ascending=True)
df_combined = df_combined.reset_index(drop=True)
# Berechne neue Einträge
new_entries = len(df_combined) - len(self.df_existing) if self.df_existing is not None else len(df_combined)
print(f"✅ Merge abgeschlossen:")
print(f" Vorher: {len(self.df_existing) if self.df_existing is not None else 0} Ziehungen")
print(f" Neu hinzugefügt: {new_entries} Ziehungen")
print(f" Nachher: {len(df_combined)} Ziehungen")
return df_combined
def save_updated_data(self, df: pd.DataFrame) -> bool:
"""
Speichert aktualisierte Daten.
Args:
df: DataFrame zum Speichern
Returns:
True bei Erfolg
"""
try:
# Format Datum als String
df_to_save = df.copy()
df_to_save['datum'] = df_to_save['datum'].dt.strftime('%Y-%m-%d')
# Speichern
df_to_save.to_csv(self.data_file, sep=';', index=False)
print(f"\n💾 Daten gespeichert: {self.data_file}")
print(f" {len(df)} Ziehungen total")
if len(df) > 0:
latest = df['datum'].max()
print(f" Neueste Ziehung: {latest.strftime('%Y-%m-%d')}")
return True
except Exception as e:
print(f"❌ Fehler beim Speichern: {e}")
# Restore backup
if self.backup_file and os.path.exists(self.backup_file):
print("🔄 Stelle Backup wieder her...")
shutil.copy2(self.backup_file, self.data_file)
print("✅ Backup wiederhergestellt")
return False
def update(self, source: str = 'auto', dry_run: bool = False) -> bool:
"""
Führt komplettes Update durch.
Args:
source: Datenquelle ('auto', 'eurojackpot_de', 'euro_jackpot_net', 'manual')
dry_run: Wenn True, keine Änderungen speichern
Returns:
True bei Erfolg
"""
print(f"\n{'🧪 DRY RUN MODE' if dry_run else '🚀 UPDATE STARTEN'}")
print("=" * 60)
# 1. Lade existierende Daten
if not self.load_existing_data():
return False
# 2. Backup erstellen
if not dry_run:
self.create_backup()
# 3. Hole neue Ziehungen
new_draws = self.fetch_new_draws(source=source)
if not new_draws:
print("\n✅ Keine neuen Ziehungen gefunden - Daten sind aktuell")
return True
# 4. Merge mit existierenden Daten
df_updated = self.merge_with_existing(new_draws)
# 5. Speichern
if not dry_run:
return self.save_updated_data(df_updated)
else:
print("\n🧪 DRY RUN - Keine Änderungen gespeichert")
print(f" Würde {len(df_updated)} Ziehungen speichern")
return True
def main():
"""Hauptfunktion für interaktive Nutzung."""
print("=" * 70)
print(" EUROJACKPOT HISTORICAL DATA UPDATER")
print("=" * 70)
print()
# Konfiguration
default_data_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
print("📁 KONFIGURATION")
print("=" * 60)
print(f"Standard-Datei: {default_data_file}")
print()
use_default = input("Standard-Datei verwenden? (j/n): ").lower().strip()
if use_default in ['j', 'ja', 'y', 'yes', '']:
data_file = default_data_file
else:
data_file = input("Pfad zur Datendatei: ").strip()
print()
print("🌐 DATENQUELLE WÄHLEN")
print("=" * 60)
print("1. Auto (versucht alle Quellen)")
print("2. eurojackpot.de")
print("3. euro-jackpot.net")
print("4. Manuelle Eingabe")
print()
source_choice = input("Wahl (1-4): ").strip()
source_map = {
'1': 'auto',
'2': 'eurojackpot_de',
'3': 'euro_jackpot_net',
'4': 'manual'
}
source = source_map.get(source_choice, 'auto')
print()
print("🧪 DRY RUN?")
print("=" * 60)
print("Dry Run = Keine Änderungen, nur Vorschau")
dry_run_choice = input("Dry Run aktivieren? (j/n): ").lower().strip()
dry_run = dry_run_choice in ['j', 'ja', 'y', 'yes']
print()
# Update durchführen
updater = EurojackpotDataUpdater(data_file)
success = updater.update(source=source, dry_run=dry_run)
print()
print("=" * 70)
if success:
print("✅ UPDATE ERFOLGREICH ABGESCHLOSSEN")
else:
print("❌ UPDATE FEHLGESCHLAGEN")
print("=" * 70)
return success
if __name__ == "__main__":
import sys
# Einfache CLI
if len(sys.argv) > 1:
# Kommandozeilen-Modus
data_file = sys.argv[1]
source = sys.argv[2] if len(sys.argv) > 2 else 'auto'
dry_run = '--dry-run' in sys.argv
updater = EurojackpotDataUpdater(data_file)
success = updater.update(source=source, dry_run=dry_run)
sys.exit(0 if success else 1)
else:
# Interaktiver Modus
main()
-210
View File
@@ -1,210 +0,0 @@
#!/usr/bin/env python3
"""
Eurojackpot Zahlen-Umschlüsselung
Fügt neue Spalten z1, z2, z3, z4, z5 hinzu mit umschlüsselten Werten:
1-5 → 1, 6-10 → 2, 11-15 → 3, 16-20 → 4, 21-25 → 5,
26-30 → 6, 31-35 → 7, 36-40 → 8, 41-45 → 9, 46-50 → 10
"""
import pandas as pd
def convert_number_to_group(number):
"""Konvertiert eine Zahl (1-50) in eine Gruppe (1-10)."""
if 1 <= number <= 5:
return 1
elif 6 <= number <= 10:
return 2
elif 11 <= number <= 15:
return 3
elif 16 <= number <= 20:
return 4
elif 21 <= number <= 25:
return 5
elif 26 <= number <= 30:
return 6
elif 31 <= number <= 35:
return 7
elif 36 <= number <= 40:
return 8
elif 41 <= number <= 45:
return 9
elif 46 <= number <= 50:
return 10
else:
return 0 # Fehlerfall
def process_number_conversion():
"""Führt die Zahlenumschlüsselung durch."""
# Eingabedatei laden
input_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/data/AlleEurojackpotzahlen.csv"
print("🔢 EUROJACKPOT ZAHLEN-UMSCHLÜSSELUNG")
print("="*50)
# Daten laden
print(f"📁 Lade Daten aus: AlleEurojackpotzahlen.csv")
df = pd.read_csv(input_file, sep=';')
print(f"✅ {len(df)} Ziehungen geladen")
# Umschlüsselungsschema anzeigen
print(f"\n📋 UMSCHLÜSSELUNGSSCHEMA:")
print("="*30)
ranges = [
(1, 5, 1), (6, 10, 2), (11, 15, 3), (16, 20, 4), (21, 25, 5),
(26, 30, 6), (31, 35, 7), (36, 40, 8), (41, 45, 9), (46, 50, 10)
]
for start, end, group in ranges:
print(f"Zahlen {start:2}-{end:2} → Gruppe {group:2}")
# Neue Spalten erstellen
print(f"\n🔄 Erstelle neue Spalten z1, z2, z3, z4, z5...")
source_columns = ['Z1', 'Z2', 'Z3', 'Z4', 'Z5']
target_columns = ['z1', 'z2', 'z3', 'z4', 'z5']
for source_col, target_col in zip(source_columns, target_columns):
df[target_col] = df[source_col].apply(convert_number_to_group)
print(f" {source_col} → {target_col} ✅")
# Erste 5 Beispiele anzeigen
print(f"\n📊 BEISPIEL-UMSCHLÜSSELUNGEN (erste 5 Ziehungen):")
print("="*60)
print(f"{'Datum':<12} {'Z1→z1':<8} {'Z2→z2':<8} {'Z3→z3':<8} {'Z4→z4':<8} {'Z5→z5':<8}")
print("-" * 60)
for i in range(min(5, len(df))):
row = df.iloc[i]
datum = row['datum']
conversions = []
for source_col, target_col in zip(source_columns, target_columns):
original = row[source_col]
converted = row[target_col]
conversions.append(f"{original:2}→{converted}")
print(f"{datum:<12} {conversions[0]:<8} {conversions[1]:<8} {conversions[2]:<8} {conversions[3]:<8} {conversions[4]:<8}")
# Statistiken der Umschlüsselung
print(f"\n📈 STATISTIKEN DER UMSCHLÜSSELTEN WERTE:")
print("="*45)
# Häufigkeit der Gruppen über alle Positionen
all_converted_values = []
for target_col in target_columns:
all_converted_values.extend(df[target_col].tolist())
from collections import Counter
group_counts = Counter(all_converted_values)
print(f"Verteilung der Gruppen (1-10) über alle Positionen:")
total_values = len(all_converted_values)
for group in range(1, 11):
count = group_counts.get(group, 0)
percentage = (count / total_values) * 100
original_range = f"{(group-1)*5 + 1}-{group*5}"
print(f"Gruppe {group:2} ({original_range:5}): {count:4}x ({percentage:5.1f}%)")
# Statistiken pro Position
print(f"\n📊 VERTEILUNG PRO POSITION:")
print("="*35)
for i, target_col in enumerate(target_columns, 1):
position_counts = Counter(df[target_col])
print(f"\nPosition z{i} ({target_col}):")
for group in range(1, 11):
count = position_counts.get(group, 0)
percentage = (count / len(df)) * 100
print(f" Gruppe {group:2}: {count:3}x ({percentage:4.1f}%)")
# Häufigste Kombinationen der umschlüsselten Werte
print(f"\n🎯 HÄUFIGSTE KOMBINATIONEN (umschlüsselt):")
print("="*45)
# Kombinationen als Strings erstellen
df['kombination_umschluesselt'] = df.apply(
lambda row: f"{row['z1']}-{row['z2']}-{row['z3']}-{row['z4']}-{row['z5']}", axis=1
)
combination_counts = Counter(df['kombination_umschluesselt'])
print(f"Top 15 Kombinationen (z1-z2-z3-z4-z5):")
for i, (combination, count) in enumerate(combination_counts.most_common(15), 1):
percentage = (count / len(df)) * 100
print(f"{i:2}. {combination:15} {count:3}x ({percentage:4.1f}%)")
# Muster-Analyse
print(f"\n🔍 MUSTER-ANALYSE:")
print("="*25)
# Aufsteigende Kombinationen
ascending_count = 0
descending_count = 0
for _, row in df.iterrows():
values = [row[col] for col in target_columns]
if values == sorted(values):
ascending_count += 1
elif values == sorted(values, reverse=True):
descending_count += 1
print(f"Aufsteigende Kombinationen: {ascending_count} ({(ascending_count/len(df)*100):.1f}%)")
print(f"Absteigende Kombinationen: {descending_count} ({(descending_count/len(df)*100):.1f}%)")
# Gleiche Werte
same_values_stats = {}
for num_same in range(2, 6):
count = 0
for _, row in df.iterrows():
values = [row[col] for col in target_columns]
value_counts = Counter(values)
if max(value_counts.values()) >= num_same:
count += 1
same_values_stats[num_same] = count
print(f"Mindestens {num_same} gleiche Werte: {count} ({(count/len(df)*100):.1f}%)")
# Bereiche der umschlüsselten Werte
print(f"\n📋 BEREICHSANALYSE (umschlüsselt):")
print("="*35)
# Niedrig (1-3), Mittel (4-7), Hoch (8-10)
for i, target_col in enumerate(target_columns, 1):
low_count = sum(1 for val in df[target_col] if 1 <= val <= 3)
mid_count = sum(1 for val in df[target_col] if 4 <= val <= 7)
high_count = sum(1 for val in df[target_col] if 8 <= val <= 10)
low_pct = (low_count / len(df)) * 100
mid_pct = (mid_count / len(df)) * 100
high_pct = (high_count / len(df)) * 100
print(f"z{i}: Niedrig(1-3)={low_pct:4.1f}% | Mittel(4-7)={mid_pct:4.1f}% | Hoch(8-10)={high_pct:4.1f}%")
# Ausgabedatei speichern
output_file = "/Users/sebastianfrohlich/Library/Mobile Documents/com~apple~CloudDocs/Jupyter Notebooks/Eurojackpot/AlleEurojackpotzahlen_umschluesselt.csv"
print(f"\n💾 DATEI SPEICHERN:")
print("="*25)
# Spalten neu ordnen (Original + neue Spalten)
column_order = ['tag', 'datum', 'Z1', 'Z2', 'Z3', 'Z4', 'Z5', 'z1', 'z2', 'z3', 'z4', 'z5', 'SZ1', 'SZ2', 'kombination_umschluesselt']
# Prüfen welche Spalten existieren
available_columns = [col for col in column_order if col in df.columns]
df_output = df[available_columns]
df_output.to_csv(output_file, sep=';', index=False)
print(f"✅ Umschlüsselte Daten gespeichert: AlleEurojackpotzahlen_umschluesselt.csv")
print(f"📊 Anzahl Spalten: {len(df_output.columns)}")
print(f"📈 Anzahl Zeilen: {len(df_output)}")
print(f"\n🔍 NEUE SPALTEN:")
for col in ['z1', 'z2', 'z3', 'z4', 'z5', 'kombination_umschluesselt']:
if col in df_output.columns:
print(f" ✅ {col}")
return df_output
if __name__ == "__main__":
result_df = process_number_conversion()