Newer
Older
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
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Hausaufgabe 2 - Python, XML, API\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Einleitung\n",
"\n",
"Wir haben uns in den letzten Sitzungen damit beschäftigt, wie man mit JupyterNotebooks arbeitet und wie man mit Python APIs abfragt, Dateien herunterlädt, XML parst und CSV-Dateien anlegt.\n",
"\n",
"Am Beispiel der CoReMa-Edition haben wir die XML-TEI-Dokumente der einzelnen Handschriften heruntergeladen. Diese Dateien enthalten die gesamten Handschriften mit den getaggten Rezepten.\n",
"\n",
"### Ziel\n",
"\n",
"In dieser Hausaufgabe sollen alle Schritte mit kleinen Änderungen wiederholt werden. Ziel ist es, statt der Handschriften die einzelnen Rezepte herunterzuladen und zu speichern. Aus allen Rezepten sind dann vorgegebene Informationen auszulesen, die dann in einer CSV für die spätere Auswertung in der Übung gespeichert werden.\n",
"\n",
"### Vorgehen\n",
"\n",
"Um die Aufgabe zu bearbeiten, muss diese Datei als JupyterNotebook geladen und die folgenden Skripte angepasst werden. Das Material aus den letzten Stunden ist Voraussetzung für die Lösung. Oft wird nur der vorhandene Code kopiert und hier eingefügt werden oder ein String oder eine URL angepasst werden müssen, an anderen Stellen werden auch selbstständig Lösungen entwickelt werden müssen.\n",
"\n",
"**Hinweis**: Oft kannst du den Inhalt einer Variablen mit `print(VARIABLE)` ausgeben und dir so anschauen, welchen Stand die Variable aktuell hat oder ob ein Fehler direkt ersichtlich wird.\n",
"\n",
"### Abgabe\n",
"\n",
"Die Abgabe erfolgt spätestens in einer Woche am 07.01.25, 12:00.\\\n",
"Bitte bearbeitet diese Datei entsprechend der Aufgabe und testet aus, ob die erwarteten Ergebnisse vorhanden sind.\\\n",
"Sendet die Hausaufgabe an alle Dozierende: fechner@bbaw.de, ruth.sander@bbaw.de und jan.wierzoch@bbaw.de."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## --- Teil 1: Sammeln und abspeichern der Rezepte als XML-Dateien ---\n",
"## Skript-Entwicklung\n",
"\n",
"### Schritt 1.1: Bibliotheken importieren\n",
"Als ersten Schritt werden wir die benötigten Bibliotheken laden. Es handelt sich dabei um die Bibliotheken:\n",
"\n",
"- **request**: Diese Bibliothek wird verwendet, um HTTP-Anfragen wie GET oder POST zu stellen und Antworten von URLs zu erhalten.\n",
"- **ElementTree**: Diese Bibliothek dient dazu, XML-Dateien zu laden und zu verarbeiten. Sie ermöglicht es, spezifische Elemente und Inhalte aus XML-Dateien zu extrahieren."
]
},
{
"cell_type": "code",
"# ToDo: Hier den Import der benötigten Bibliotheken einfügen.\n",
"import requests\n",
"import xml.etree.ElementTree as ET"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Schritt 1.2: IDs der Manuskripte laden\n",
"Wir laden zunächst alle IDs der Manuskripte mit annotierten Rezepten in die Variable `msIds`. \n",
"\n",
"Hinweis: wir haben etwas ähnliches in der Aufgabe 4 (APIs) gemacht. Nicht vergessen die Variablen ggf. umzubenennen!"
]
},
{
"cell_type": "code",
"metadata": {},
"outputs": [],
"source": [
"# ToDo: Defiere die base URL für den OAI-PMH Endpoint\n",
"base_url = 'https://gams.uni-graz.at/archive/objects/context:corema.recipes/datastreams/METADATA/content'\n",
"\n",
"# ToDo: Schick ein 'request' an den Endpoint\n",
"response = requests.get(base_url, params={})\n",
"if response.status_code != 200:\n",
" print(f'Error: {response.status_code}')\n",
"\n",
"# ToDo: Definiere ein Namespace dictionary mit 'sparql' als key\n",
"ns = {'sparql': 'http://www.w3.org/2001/sw/DataAccess/rf1/result'}\n",
"\n",
"# ToDo: Definierte dein Endpoint-responce als 'root', damit du es weiter verarbeiten kannst.\n",
"# ToDo: Baue eine Schleife um all IDs aus der Resonce zu iterieren, speicher diese in eine die Liste msIds. \n",
"recipesIds = []\n",
"for id_no in root.findall('.//sparql:identifier', ns):\n",
" id = id_no.text\n",
" recipesIds.append(id)"
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"['o:corema.pa1.recipes', 'o:corema.b5.recipes', 'o:corema.b6.recipes', 'o:corema.wo8.recipes', 'o:corema.wo3.recipes', 'o:corema.w1.recipes', 'o:corema.bs1.recipes', 'o:corema.er1.recipes', 'o:corema.ds1.recipes', 'o:corema.gr1.recipes', 'o:corema.m11.recipes', 'o:corema.wo10.recipes', 'o:corema.k1.recipes', 'o:corema.w4.recipes', 'o:corema.db1.recipes', 'o:corema.b3.recipes', 'o:corema.bs2.recipes', 'o:corema.wo11.recipes', 'o:corema.b4.recipes', 'o:corema.h2.recipes', 'o:corema.br1.recipes', 'o:corema.so1.recipes', 'o:corema.wo7.recipes', 'o:corema.a1.recipes', 'o:corema.wo9.recipes', 'o:corema.wo1.recipes', 'o:corema.b2.recipes', 'o:corema.b1.recipes']\n"
]
}
],
"source": [
"print(recipesIds)"
]
},
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Schritt 1.3: IDs der Rezepte extrahieren\n",
"\n",
"Als nächstes bauen wir eine Schleife und iterieren über die Rezept-Manuskripte in `msIds`. Für jeden Eintrag laden wir die einzelnen IDs der Rezepte.\n",
"\n",
"Die Manuskripte konnten wir über den Aufruf der URL <https://gams.uni-graz.at/archive/objects/context:corema.recipes/datastreams/METADATA/content> erhalten. (Siehe vorheriger Schritt.)\n",
"\n",
"Um die IDs der einzelnen Rezepte zu erhalten, müssen wir für jedes Manuskript eine URL der Form <https://gams.uni-graz.at/archive/objects/context:corema.pa1/datastreams/METADATA/content> aufrufen. Das Ergebnis eines Aufrufs einer einzelnen Handschrift ist:\n",
"\n",
"```xml\n",
"<sparql xmlns=\"http://www.w3.org/2001/sw/DataAccess/rf1/result\">\n",
" <head>\n",
" <variable name=\"container\"/>\n",
" <variable name=\"cid\"/>\n",
" <variable name=\"pid\"/>\n",
" <variable name=\"model\"/>\n",
" <variable name=\"ownerId\"/>\n",
" <variable name=\"createdDate\"/>\n",
" <variable name=\"lastModifiedDate\"/>\n",
" <variable name=\"title\"/>\n",
" <variable name=\"identifier\"/>\n",
" </head>\n",
" <results>\n",
" <result>\n",
" <container>Context for all recipes in manuscript \"Pa1\"</container>\n",
" <cid>context:corema.pa1</cid>\n",
" <pid uri=\"info:fedora/o:corema.pa1.13\"/>\n",
" <model uri=\"info:fedora/cm:TEI\"/>\n",
" <ownerId>corema</ownerId>\n",
" <createdDate datatype=\"http://www.w3.org/2001/XMLSchema#dateTime\">2021-06-22T15:43:26.602Z</createdDate>\n",
" <lastModifiedDate datatype=\"http://www.w3.org/2001/XMLSchema#dateTime\">2023-03-03T01:04:21.423Z</lastModifiedDate>\n",
" <title>Cooking Recipe for Chicken flat cake</title>\n",
" <identifier>o:corema.pa1.13</identifier>\n",
" </result>\n",
" ...\n",
"```\n",
"\n",
"### Schritt 1.4: Ergänze das folgende Skript, wie in den Kommentaren beschrieben:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Wir initialisieren eine leere Liste der Rezept-IDs. Hier werden wir alle IDs sammeln, die in den einzelnen Handschriften vorhanden sind.\n",
"recipesIds = []\n",
"\n",
"# Hier iterieren (\"schleifen\") wir über die Manuskripte, die du in msIds gesammelt hast:\n",
"for msId in msIds:\n",
" \n",
" # Die URL sieht wie folgt aus: \n",
" # https://gams.uni-graz.at/archive/objects/context:corema.pa1/datastreams/METADATA/content\n",
" # Unsere gesammelten IDs sehen so aus: o:corema.b5.recipes\n",
" # Die IDs müssen bereinigt werden, damit sie dem Format der URL entsprechen. Dafür muss das Prefix \"o:\" und das Suffix \".recipes\" entfernt werden.\n",
" \n",
" # Mit der Funktion '.replace(old_text, new_text)' ersetzen wir zunächst das Prefix \"o:\" durch einen leeren String \"\".\n",
" id_without_prefix = msId.replace('o:','')\n",
" \n",
" # ToDo: Ersetze nun selbst auch das Suffix \".recipes\" durch einen leeren String. Verwende als Ausgangspunkt die Variable \"id_without_prefix\".\n",
" id = REPLACE HERE\n",
" \n",
" # ToDo: Baue nun die neue URL im oben genannten Format. Nutze die folgende Syntax, um String miteinander zu verketten: \n",
" # \"http://example.com/path/\" + variable + \"/end/of/path\"\n",
"\n",
" base_url = URL HERE\n",
"\n",
" # Wir fragen nun die URL an und bekommen eine Antwort im oben beschriebenen SPARQL Format.\n",
" response = requests.get(base_url, params={})\n",
" if response.status_code != 200:\n",
" print(f'Error: {response.status_code}')\n",
" \n",
" ns = {'sparql': 'http://www.w3.org/2001/sw/DataAccess/rf1/result'}\n",
" root = ET.fromstring(response.content)\n",
"\n",
" # Prüfe, ob der XPath-Ausdruck in der folgenden Zeile auch für die aktuelle Antwort zutrifft und korrigiere, falls nötig.\n",
" for recipeId in root.findall('.//sparql:identifier', ns):\n",
" # Für jedes gefundene Rezept wird die ID der Rezeptliste hinzugefügt:\n",
" recipesIds.append(recipeId.text)\n",
"\n",
"# Wenn alles funktioniert, gibt uns der folgende Befehl alle IDs aus:\n",
"print(recipesIds)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Schritt 1.5: Rezept abrufen und abspeichern\n",
"\n",
"Äquivalent zur Aufgabe 5 (API) rufen wir nun die einzelnen Rezepte ab und speichern sie im Ordner `/xml`. **Hinweis**: ggf. Namen der Variablen überprüfen; **Hinweis**: Der Ordner `/xml` muss bereits existieren."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ToDo: Schleife durch alle rezept IDs, die in recipiesIds abgespeichert sind.\n",
"\n",
"# Innerhalb der Schleife:\n",
"## ToDo: definiere eine url Variable und bau ein Link nach folgendem Format: 'https://gams.uni-graz.at/o:corema.pa1.73/TEI_SOURCE'\n",
"\n",
"## ToDo: definiere dein 'response'\n",
"\n",
"## ToDo: definiere die Variable 'xml' und befülle sie mit deinem 'responce' in utf-8 Format. \n",
"\n",
"## ToDo: definiere dein 'filename'. Hinweis: vergiss nicht den entsprechenden Ordner anzulegen/zubenennen. \n",
"# Hinweis: Doppelpunkt in der ID kann zu Problemen füheren, auch besser ersetzen!\n",
"\n",
"## ToDo: öffene die Datei und befülle sie mit deiner 'xml' Variable "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## --- Teil 2: Alle Zutaten sammeln und als CSV-Datei abspeicher ---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nun wollen wir etwas mit den gesammelten XML-Dateien machen. Unser Ziel ist es eine CSV-Datei zu erstellen, die die gesammelten Informationen von den ersten 50 Rezepten in unserem Ordner enthält. Jede Zeile der CSV entspricht einer Zutatnennung in einem Rezept. Folgende Informationen sollen enthalten sein: Id des Rezepts, Id der Zutat, Original Name der Zutat (Label) und der englische Name der Zutat. Dein Endergebnis sollte ungefähr so aussehen: {['rezept-1','zutat-01','Milch', 'milk'], ['rezept-1','zutat-02','salz', 'salt'], ['rezept-2','zutat-99','Brot', 'bread'], ...}\n",
"\n",
"Schritte:\n",
"- 2.1: importiere benötigte Packages/Bibliotheken (os, csv)\n",
"- 2.2: Definiere eine Liste wo wir ALLE Informationen sammeln. z.B. 'joint_ingrediants_list'\n",
"- 2.3: Definiere die benötigten Namespaces ('xml', 'tei') in einem dictionary. \n",
"- 2.4: Erstelle eine Verbindung zu deinem XML Ordner und iteriere durch die ersten 50 Dateien\n",
"- 2.5: Pro Rezept, definiere 'rezept-id' und befülle die Variable entsprechend\n",
"- Pro Zutat: \n",
" 2.6: erstelle eine Liste zum zwischenspeichern (z.B. 'zutat_info'). Das macht es leichter für uns, alle wichtigen Informationen zu sammeln um sich später als einen Eintag in die 'joint_ingrediants_list' zu speichern.\n",
" 2.7: definere 'zutat-id', 'original-label', 'eng-label' und befülle die Variable entsprechend. Hinweis: Wir haben etwas ähnliches in der 4. Aufgabe (XML mit Python) gemacht. Ggf. könnt ihr auch in der XML-Datei nachgucken, wo die Informationen stehen.\n",
" 2.8: Schreibe alle Informationen zur Zutat in die 'zutat_info' Liste.\n",
" 2.9: Füge die 'zutat_infos' Liste in die 'joint_ingrediants_list' Liste hinzu (append)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ToDo: import Packages\n",
"\n",
"\n",
"# ToDo: Definiere die Übergreifenden Liste aller Zutaten und deren Informationen\n",
"\n",
"\n",
"# ToDo: Definiere die benötigten Namespaces\n",
"namespace = {}\n",
"\n",
"# ToDo: Erstelle eine Verbindung zu deinem XML Ordner und iteriere durch die ersten 50 Ordner\n",
"directory= 'TODO'\n",
"counter = 0 # Das ist unser counter mit dem wir von 0 bis 50 Zählen. So wissen wir wann unser Loop stoppen soll.\n",
"for filename in os.listdir(directory):\n",
" if counter >= MAX_NUMBER : # Wenn unser counter gleich 50 oder höher ist mache -->\n",
" break # endet die Schleife\n",
" \n",
" filepath = os.path.join(directory, filename)\n",
" if not os.path.isfile(filepath): # Überprüft den Type. Treffer wird übersprungen, wenn es nicht eine Datei (z.B. Bilder) ist.\n",
" continue\n",
" \n",
" try:\n",
" tree = ET.parse(filepath) \n",
" # ToDo: Definiere das Wurzelelement\n",
" root = TODO\n",
"\n",
"\n",
" # ToDo: Navigiere zum Element des Rezepts\n",
" rezept_elem = root.find('TODO:XPATH')\n",
" if rezept_elem is not None: # wenn das Element nicht leer ist mache -->\n",
" \n",
" rezept_id = rezept_elem.get('{http://www.w3.org/XML/1998/namespace}id') # Hier wird die ID des Rezepts gesucht und abgespeichert\n",
" \n",
" # Pro Zutat im Rezept:\n",
" for zutat in rezept_elem.findall():\n",
" # ToDo 2.6: erstelle eine Liste in der wir die Informationen zwischenlagern\n",
" \n",
" # ToDo 2.7: Definere 'zutat-id', 'original-label', 'eng-label' und befülle die Variable entsprechend\n",
" \n",
" # ToDo 2.8: Schriebe diese drei Werte UND die ID des Rezepts in die zutat_infos Liste. Hinweis: mit print(zutat_info) testen.\n",
" # Das Ergebnis sollte ungefähr so aussehen: ['rezept-1','zutat-01','Milch', 'milk']\n",
" \n",
"\n",
" # ToDo 2.9: Append die 'zutat_infos Liste in die 'joint_ingrediants_list' Liste\n",
"\n",
"\n",
"\n",
" counter += 1 # Pro Durchlauf der Schleife zählt der Counter eins hoch\n",
"\n",
" except ET.ParseError as e:\n",
" print(f\"Error parsing file {filename}: {e}\")\n",
" except Exception as e:\n",
" print(f\"Error processing file {filename}: {e}\")\n",
"\n",
"# Test ob die Liste richtig aussieht. Sie sollte ungefähr so aussehen:\n",
"# {['rezept-1','zutat-01','Milch', 'milk'], ['rezept-1','zutat-02','salz', 'salt'], ['rezept-2','zutat-99','Brot', 'bread'], ...}\n",
"#pprint.pprint(joint_ingrediants_list)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Schritt 2.10.: Als nächstest wollen wir unsere gesamte Liste mit Zutat-Informationen als eine CSV-Datei exportieren:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import csv\n",
"\n",
"# Hier definieren wir den Ablageort der Datei \n",
"output_csv = \"./csv/\" + \"alle_zutaten.csv\"\n",
"\n",
"# Hier wird die Datei im Schreibmodus geöffnet und erstellt ein CSV-Schreiber\n",
"with open(output_csv, mode='w', newline='', encoding=\"utf-8\") as file:\n",
" writer = csv.writer(file)\n",
" \n",
" # ToDo: Schreibe eine Überschrift für die Spalten \"rezept_id\", \"zutat_id\", \"original\" und \"eng_label\".\n",
" # Hinweis: Ihr schreibt eine Liste mit den genannten Werte in die erste Reihe der CSV Datei\n",
" writer.writerow(TODO)\n",
" \n",
" # ToDo: Schleif durch die Liste 'joint_ingredients_list' und schreib jede Reihe aus der Liste als neuen Eintrag in die CSV-Datei.\n",
" for reihe in TODO:\n",
" writer.writerow(reihe) # Hier wird ein neuer Eintrag in die CSV geschrieben \n",
"\n",
"print(f\"Zutaten werden exportiert {output_csv}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## --- Teil 3: Rezepte nach Zutaten filtern ---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Im letzten Abschnitt wird es Ihre Aufgabe sein, die bestehende CSV-Datei wieder einzulesen und nur die Rezepte (Rezept-IDs) auszugeben, die eine bestimmte Zutat enthalten. Achten Sie darauf, dass die IDs nicht doppelt ausgegeben werden! Verwenden Sie als ID `Q10987` (= Honig), probieren Sie aber gerne auch andere IDs aus."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Importieren des benötigten Packages\n",
"import csv"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Einlesen der CSV-Datei \"alle_zutaten.csv\" aus dem Ordner \"/csv\" in UTF-8 Kodierung. Den Inhalt in der Variablen \"inputCsv\" als Python Dictionary speichern.\n",
"inputFile = open(\"./csv/alle_zutaten.csv\", encoding=\"utf-8\")\n",
"inputCsv = csv.DictReader(inputFile)\n",
"\n",
"# Filter: Alle Rezepte mit einer bestimmten Zutat (= zutat_id) ausgeben. Welche die zu filternde Zutat ist, wird in der Variable \"ingredient\" festgelegt.\n",
"# Als Ergebnisliste wird die leere Liste \"filteredRecipies\" angelegt, die im nächsten Schritt zu befüllen ist.\n",
"ingredient = 'Q10987' # Honig\n",
"filteredRecipes = []\n",
"\n",
"# Filter implementieren\n",
"# TODO 3.1: Implementieren Sie eine Schleife, die über \"inputCsv\" iteriert.\n",
"\n",
" # TODO 3.2: Prüfen Sie pro Eintrag mit einer if-Bedingung, ob der Wert im Schlüssel (Key) \"rezept_id\" der gleiche ist wie in der Filtervariable \"ingredient\".\n",
" # Falls der Wert gleich ist, fügen Sie ihn der Liste \"filteredRecipes\" hinzu.\n",
"\n",
"\n",
"# TODO 3.3: Ausgabe (Hinweis: Achten Sie darauf, dass jede Rezept-ID nur einmal ausgegeben wird! Wandeln Sie die Liste dazu mit \"set()\" in ein Set um. Sets sind ähnlich wie Listen, enthalten aber jeden Wert nur einmal.)\n",
"\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Nun sollen die gefilterten Rezepte wieder im Format `rezept_id`, `zutat_id`, `original`, `eng_label` ausgeben ausgegeben und in einer Datei abgespeichert werden, wobei pro Rezept jede Zutat nur einmal vorkommen soll."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# TODO 3.4: Schauen Sie sich den Code an und versuchen Sie ihn zu verstehen. \n",
"# Wichtig ist, dass Sie verstehen, warum welcher Schritt durchgeführt wird, die Syntax ist nebensächlich. \n",
"# Wenn Sie Fragen haben, notieren Sie diese gerne im Markdown-Feld unter dem Code.\n",
"\n",
"# DictReader auf die erste Position zurücksetzen, damit die for-Schleife wieder funktioniert!\n",
"inputFile.seek(0)\n",
"\n",
"# Gefilterte Rezepte ausgeben (jede Zutat nur einmal pro Rezept)\n",
"# Zuerst wird eine Liste \"selectedRecipies\" für die gefilterten Rezepte sowie ein Hilfs-Set \"existingRecipes\" (Einmaligkeit der Zutat pro Rezept) angelegt.\n",
"existingRecipes = set()\n",
"selectedRecipes = []\n",
"\n",
"# Über den Inhalt der bisherigen CSV-Datei (Variable \"inputCsv\", siehe oben) iterieren.\n",
"for r in inputCsv:\n",
" # Zweite Schleife über die in der vorherigen Aufgabe gefilterten Rezepte.\n",
" for id in set(filteredRecipes):\n",
" # Nur wenn das Rezept aus der allgemeinen Liste auch in der gefilterten Liste \"filteredRecipes\" vorkommt UND die Zutat für das Rezept noch nicht im Hilfs-Set \"existingRecipes\" vorkommt, soll es weiterverarbeitet werden.\n",
" if r[\"rezept_id\"] == id and ((r[\"rezept_id\"], r[\"zutat_id\"]) not in existingRecipes):\n",
" existingRecipes.add((r[\"rezept_id\"], r[\"zutat_id\"]))\n",
" selectedRecipes.append(r)\n",
"\n",
"# Kontrollausgabe\n",
"for i in selectedRecipes:\n",
" print(i)\n",
"\n",
"\n",
"# Writer\n",
"# Datei zum Schreiben der Ergebnisse erstellen und für die Bearbeitung in Variable \"csv_file\" hinterlegen.\n",
"csv_file = open(f\"./csv/filtered_${ingredient}.csv\", \"w\", newline=\"\", encoding='utf-8')\n",
"\n",
"# Als Writer wird der csv.DictWriter verwendet, der Python Dictionaries in CSV-Dateien schreiben kann.\n",
"csv_writer = csv.DictWriter(csv_file, ['rezept_id', 'zutat_id', 'original', 'eng_label'])\n",
"\n",
"# Den Header der CSV-Datei (Spaltennamen) schreiben.\n",
"csv_writer.writeheader()\n",
"\n",
"# Über die Liste der ausgewählten Rezepte iterieren und pro Iteration als Zeile in die Datei schreiben.\n",
"for recipe in selectedRecipes:\n",
" csv_writer.writerow(recipe)\n",
"\n",
"# Datei für die Bearbeitung schließen.\n",
"csv_file.close()\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Hier ist Platz für Ihre Fragen:**\n"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.8"
}
},
"nbformat": 4,
"nbformat_minor": 2
}