-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.py
More file actions
279 lines (220 loc) · 7.56 KB
/
main.py
File metadata and controls
279 lines (220 loc) · 7.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
"""
Hauptskript für den OParl-Client des Bonner Ratsinformationssystems
Dieses Skript bietet eine einfache Kommandozeilenschnittstelle für den Abruf
von Meetings aus der OParl-API.
"""
import argparse
import sys
import time
from pathlib import Path
from datetime import datetime
# Import der Client-Klassen
try:
from src.oparl_client import OParlClient
from src.oparl_client_advanced import OParlClientAdvanced
except ImportError:
# Fallback für direkte Ausführung
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from src.oparl_client import OParlClient
from src.oparl_client_advanced import OParlClientAdvanced
def parse_arguments():
"""Parst die Kommandozeilenargumente"""
parser = argparse.ArgumentParser(
description="OParl-Client für das Bonner Ratsinformationssystem",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Beispiele:
python main.py # Standard-Ausführung
python main.py --advanced # Erweiterte Version mit Progress Bar
python main.py --end-date 2025-06-30 # Anderes Enddatum
python main.py --no-cache # Deaktiviere Caching
python main.py --output ./data # Anderes Ausgabeverzeichnis
""",
)
parser.add_argument(
"--base-url",
default="https://www.bonn.sitzung-online.de/public/oparl",
help="Basis-URL der OParl-API (Standard: %(default)s)",
)
parser.add_argument(
"--end-date",
default="2025-12-31",
help="Enddatum für den Filter im Format YYYY-MM-DD (Standard: %(default)s)",
)
parser.add_argument(
"--output-dir",
default="output",
help="Ausgabeverzeichnis für Dateien (Standard: %(default)s)",
)
parser.add_argument(
"--cache-dir",
default="cache",
help="Cache-Verzeichnis für API-Antworten (Standard: %(default)s)",
)
parser.add_argument(
"--rate-limit",
type=float,
default=1.0,
help="Wartezeit zwischen Requests in Sekunden (Standard: %(default)s)",
)
parser.add_argument(
"--max-retries",
type=int,
default=3,
help="Maximale Anzahl Wiederholungsversuche (Standard: %(default)s)",
)
parser.add_argument(
"--advanced",
action="store_true",
help="Verwende erweiterte Version mit Progress Bar",
)
parser.add_argument(
"--no-cache", action="store_true", help="Deaktiviere Caching von API-Antworten"
)
parser.add_argument(
"--no-progress",
action="store_true",
help="Deaktiviere Progress Bar (nur bei --advanced)",
)
parser.add_argument(
"--verbose", action="store_true", help="Aktiviere detaillierte Log-Ausgabe"
)
parser.add_argument(
"--test",
action="store_true",
help="Testmodus: Führt nur einen begrenzten Abruf durch",
)
return parser.parse_args()
def validate_arguments(args):
"""Validiert die Kommandozeilenargumente"""
# Validiere Enddatum
try:
datetime.strptime(args.end_date, "%Y-%m-%d")
except ValueError:
print(
f"Fehler: Ungültiges Datumsformat '{args.end_date}'. Erwartet: YYYY-MM-DD"
)
return False
# Validiere numerische Werte
if args.rate_limit < 0:
print("Fehler: Rate-Limit muss >= 0 sein")
return False
if args.max_retries < 0:
print("Fehler: Max-Retries muss >= 0 sein")
return False
# Validiere Verzeichnisse
try:
output_path = Path(args.output_dir)
cache_path = Path(args.cache_dir)
# Versuche Verzeichnisse zu erstellen
output_path.mkdir(exist_ok=True, parents=True)
cache_path.mkdir(exist_ok=True, parents=True)
except (OSError, PermissionError) as e:
print(f"Fehler beim Erstellen der Verzeichnisse: {e}")
return False
return True
def print_banner():
"""Gibt einen Willkommens-Banner aus"""
print("\n" + "=" * 60)
print("OPARL-CLIENT - BONNER RATSINFORMATIONSSYSTEM")
print("=" * 60)
print(f"Ausführungszeit: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
print("=" * 60 + "\n")
def run_standard_client(args):
"""Führt den Standard-Client aus"""
print("🚀 Starte Standard-Client...")
client = OParlClient(
base_url=args.base_url,
end_date=args.end_date,
output_dir=args.output_dir,
cache_dir=args.cache_dir,
rate_limit=args.rate_limit,
max_retries=args.max_retries,
)
return client.run()
def run_advanced_client(args):
"""Führt den erweiterten Client aus"""
print("🚀 Starte Erweiterten Client...")
client = OParlClientAdvanced(
base_url=args.base_url,
end_date=args.end_date,
output_dir=args.output_dir,
cache_dir=args.cache_dir,
rate_limit=args.rate_limit,
max_retries=args.max_retries,
enable_progress_bar=not args.no_progress,
enable_caching=not args.no_cache,
enable_statistics=True,
)
return client.run()
def test_mode(args):
"""Führt einen Test-Abruf durch"""
print("🧪 TESTMODUS - Begrenzter Abruf")
# Verwende erweiterten Client für bessere Kontrolle
client = OParlClientAdvanced(
base_url=args.base_url,
end_date=args.end_date,
output_dir=args.output_dir + "_test",
cache_dir=args.cache_dir + "_test",
rate_limit=args.rate_limit,
max_retries=args.max_retries,
enable_progress_bar=True,
enable_caching=False, # Kein Caching im Testmodus
enable_statistics=True,
)
# Rufe nur erste Seite ab
print("Test: Rufe erste Seite der Meetings ab...")
try:
test_url = f"{args.base_url}/meetings?body=1&page=1"
response = client.session.get(test_url, timeout=10)
response.raise_for_status()
data = response.json()
meetings_count = len(data.get("data", []))
print(f"✅ Test erfolgreich: {meetings_count} Meetings auf Seite 1 gefunden")
print(f"📊 API-Response-Struktur: {list(data.keys())}")
if meetings_count > 0:
sample_meeting = data["data"][0]
print(f"📅 Beispiel-Meeting: {sample_meeting.get('name', 'Unbekannt')}")
print(f"🕐 Start: {sample_meeting.get('start', 'Unbekannt')}")
return True
except Exception as e:
print(f"❌ Test fehlgeschlagen: {e}")
return False
def main():
"""Hauptfunktion"""
args = parse_arguments()
# Validiere Argumente
if not validate_arguments(args):
sys.exit(1)
# Banner anzeigen
print_banner()
# Testmodus
if args.test:
success = test_mode(args)
sys.exit(0 if success else 1)
# Hauptausführung
try:
start_time = time.time()
if args.advanced:
success = run_advanced_client(args)
else:
success = run_standard_client(args)
duration = time.time() - start_time
print(f"\n⏱️ Gesamtdauer: {duration:.2f} Sekunden")
if success:
print("\n✅ Abruf erfolgreich abgeschlossen!")
else:
print("\n⚠️ Abruf mit Warnungen abgeschlossen")
except KeyboardInterrupt:
print("\n\n⏹️ Abruf durch Benutzer abgebrochen")
sys.exit(1)
except Exception as e:
print(f"\n❌ Unbehandelter Fehler: {e}")
if args.verbose:
import traceback
traceback.print_exc()
sys.exit(1)
if __name__ == "__main__":
main()