Seite 1 von 1
csv-Liste auslesen und ausgeben
Verfasst: Sonntag 11. August 2019, 09:22
von vertretung
Hallo,
ich hab vor aus einer csv-Liste die Zeilen auszugeben in denen in der ersten Spalte ein bestimmtes Wort steht. Ursprünglich waren die Daten in einem HTML-Code..die hab ich dann mit bs4 in eine csv-Datei geworfen und kann sie auch problemslos aufrufen. Nur versteh ich nicht wie man das ohne RE machen kann. Meine Ansätze hab ich damit gemacht und es geschafft das Wort auszugeben, aber nicht die ganzen anderen Daten aus der Zeile
Hier ist meine csv Datei
Code: Alles auswählen
5a|Do|4.|xxxxx|/|BK|xxxxx|BK|KR2|Raum�nderung
5c|Do|2.|xxxxx|/|Geo|xxxxx|Vertr.|S308
5c|Do|5.|xxxxx|/|Med|xxxxx|Vertr.|050
5c|Do|6.|xxxxx|/|Med|entf�llt
5e|Do|1.|xxxxx|/|BK|entf�llt
5e|Do|2.|xxxxx|/|BK|xxxxx|Vertr.|S305|Raum�nderung
5e|Do|5.|xxxxx|/|M|xxxxx|M|S305|Zusatzstunde
5e|Do|6.|xxxxx|/|M|xxxxx|M|S305|Zusatzstunde
6b|Do|4.|xxxxx|/|Bio|xxxxx|KL|S306|statt|Fr|29.|Mrz|6.|Std.
6bF|Do|1.|xxxxx|/|F|entf�llt
6d|Do|2.|xxxxx|/|Bio|entf�llt|gehalten|am|Do|21.|Mrz|1.|Std.
6d|Do|2.|xxxxx|/|Bio|xxxxx|M|S107|statt|Do|21.|Mrz|1.|Std.
6d|Do|4.|xxxxx|/|E|xxxxx|E|S205|Raum�nderung
7b|Do|4.|xxxxx|/|L|xxxxx|BK|KR|Zusatzstunde
Und jetzt will ich die Zeile zB nur ausgeben, wenn in dem dazugehörigen 1. Feld 6d steht.
Code: Alles auswählen
for absatz in absaetze:
liste = absatz.text.split()
with open('csvfile.csv', 'a', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter='|')
writer.writerow(liste)
mylist = liste
r = re.compile(".*8a")
newlist = list(filter(r.match, mylist))
print(newlist)
Das hab ich bisher..damit kommt:
Tut mir leid..ich bin noch ein Anfänger und versuche mir das beizubringen, aber an dem Punkt komm ich einfach nicht weiter.
Danke schonmal im Voraus
Re: csv-Liste auslesen und ausgeben
Verfasst: Sonntag 11. August 2019, 10:56
von __blackjack__
@vertretung: Also erst einmal ist `liste` kein guter Name weil der nichts darüber sagt was in der Liste enthalten ist. Dann ist die Zuweisung von `liste` an `mylist` unsinnig, weil damit der Name a) noch schlechter wird, und b) es hier keinen Sinn macht die *selbe* Liste nun auch noch unter einem zusätzlichen anderen Namen verfügbar zu haben. Warum machst Du das?
Dann ist ein regulärer Ausdruck für *feste* Zeichenketten wie '6d' unsinnig – das würde man einfach mit ``==`` machen. Das was dann tatsächlich im Quelltext steht, also '.*8a' könnte man wahrscheinlich auch ohne regulären Ausdruck mit `str.endswith()` erledigen.
`mylist` enthält ja den gesamten Datensatz, also verarbeitest Du mit `filter()` nicht nur das erste Feld, sondern *alle*. Wenn Du nur das erste Feld auf etwas prüfen möchtest, dann mach halt auch nur das. Und halt auch nur testen und nicht irgendwas aus dem Datensatz heraus filtern. Das dann auch *vor* dem Schreiben in die Datei, denn danach ist es ja bereits in der Datei. Du musst ja vorher entscheiden ob es überhaupt geschrieben werden soll.
Da ist dann auch das ständige öffnen und schliessen der Datei für jeden Datensatz ineffizient. Die Datei würde man vor der Schleife *einmal* öffnen. Beim Modus 'a' muss man sich auch im klaren sein, dass damit nicht nur Datensätze vom aktuellen Programmlauf in der Datei landen, sondern das auch eine bereits vorhandene Datei einfach erweitert wird.
Re: csv-Liste auslesen und ausgeben
Verfasst: Sonntag 11. August 2019, 10:57
von Sirius3
Die csv-Datei sieht nicht richtig aus. Die Zeilen haben unterschiedliche Anzahl an Spalten. Vor allem das „M|S107|statt|Do|21.|Mrz|1.|Std.” sieht nicht richtig aus. Da wurde scheinbar jedes Leerzeichen durch einen Trennstrich ersetzt.
Das liegt wahrscheinlich an dem „absatz.text.split“ Wie es richtig geht kann man aber aus dem gezeigten Code nicht sagen. ›liste‹ ist dann auch ein sehr allgemeiner Variablenname, der ohne Grund in das noch schlechtere ›mylist‹ umbenannt wird.
Du suchst nach 8a bekommst aber als Ergebnis die 6d? Sehr seltsam.
In dem gezeigten Code öffnest Du ständig die Datei um eine Zeile zu schreiben. Das macht man einmal um die gesamte for-Schleife herum. Außerdem solltest Du nicht zu viel auf einmal machen.
Also nicht in die csv-Datei schreiben und nach der 8a/6d filtern.
Erstens, nur die Daten aufbereiten, wobei da was besseres als text.split benutzt werden sollte:
Code: Alles auswählen
stundenplan = []
for absatz in absaetze:
eintrag = absatz.text.split() # TODO: besseres Aufbereiten der Einträge
stundenplan.append(eintrag)
Dann kannst Du diese Datenstruktur auch einfach in eine csv-Datei schreiben:
Code: Alles auswählen
with open('csvfile.csv', 'a', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter='|')
writer.writerows(stundenplan)
Oder nach dem Filtern, was Du in Deiner Beschreibung tatsächlich geschrieben hast, nach der ersten Spalte zu filtern:
Code: Alles auswählen
klasse = '8a' # oder '6d'
for eintrag in stundenplan:
if eintrag[0] == klasse:
print(eintrag)
Re: csv-Liste auslesen und ausgeben
Verfasst: Sonntag 11. August 2019, 12:16
von vertretung
Erstmal danke für die Antworten..haben mir echt weitergeholfen. Jetzt funktioniert auch alles
Gibt es eine Möglichkeit die Tabelle so zu begrenzen, dass nur alles bis "entfällt" angezeigt wird? Also alles was sonst dahinter kommt mich nicht interessiert wie zB gehalten am..oder alles nach "gehalten" gelöscht wird bzw nicht ausgegeben wird (inklusive "gehalten").
Code: Alles auswählen
6bF|Do|1.|xxxxx|/|F|entf�llt
6d|Do|2.|xxxxx|/|Bio|entf�llt|gehalten|am|Do|21.|Mrz|1.|Std.
6d|Do|2.|xxxxx|/|Bio|xxxxx|M|S107|statt|Do|21.|Mrz|1.|Std.
Meine vorstellung war eigentlich:
Code: Alles auswählen
J2|Mi|8.|xxxxx|/|Geo1|entf�llt
J2|Mi|8.|xxxxx|/|g4|entf�llt
J2|Mi|9.|xxxxx|/|g4|entf�llt
Oder wenn ein Raum geändert wurde:
Code: Alles auswählen
J2A|Mi|3.|xxxxx|/|D1|xxxxx|D1|312|Raum�nderung
J2A|Mi|4.|xxxxx|/|D1|xxxxx|D1|312|Raum�nderung
Mein Ziel ist es nämlich die Daten gleichmäßig in den Spalten zu haben, damit ich sicher sein kann, dass alles in Spalte 2 die Stunde ist, damit ich die Daten dann später auch zB in einem String ausgeben kann
Re: csv-Liste auslesen und ausgeben
Verfasst: Sonntag 11. August 2019, 13:05
von Sirius3
Wie sieht denn Deine ursprüngliche HTML-Datei aus? Du schriebest etwas von bs4 aber davon hast Du nichts gezeigt. Ich denke, man sollte da schon die richtigen Spalten auswählen, anstatt hinterher zu versuchen, aus dem Durcheinander wieder das richtige herauszuraten.
Re: csv-Liste auslesen und ausgeben
Verfasst: Sonntag 11. August 2019, 13:12
von __blackjack__
@vertretung: Ich denke mal grundsätzlich ist ein einfaches `split()` an Leerzeichen keine Sinnvolle Verarbeitung von einem `absatz`. Die Spalte die nur '/'-Zeichen enthält ist ja sicher auch überflüssig. Und bei der dritten Spalte ist der Punkt hinter der Zahl wahrscheinlich auch nicht wirklich wichtig. Und falls bei den ausge-x-ten Spalten Namen stehen, dann könnte da vielleicht auch mal ein Leerzeichen vorkommen.
Ansonsten kann man das sowohl bei `split()` schon regeln oft maximal getrennt werden soll – schau Dir da einfach mal die möglichen Argumente an. Oder man nimmt von der gesplitteten Zeile die ersten 10 Elemente. Das wäre Grundlagen bei Listenverarbeitung.
Besser wäre es natürlich vorher schon anzusetzen.
Ach: Und bei welchem Schritt gehen Dir denn die Umlaute kaputt? Wenn man Textdateien öffnet, sollte man immer explizit eine Kodierung angeben.
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 11:24
von vertretung
Sirius3 hat geschrieben: Sonntag 11. August 2019, 13:05
Wie sieht denn Deine ursprüngliche HTML-Datei aus? Du schriebest etwas von bs4 aber davon hast Du nichts gezeigt. Ich denke, man sollte da schon die richtigen Spalten auswählen, anstatt hinterher zu versuchen, aus dem Durcheinander wieder das richtige herauszuraten.
Die sahen so aus..
Code: Alles auswählen
<tr class="normal Leselinie">
<td class="VBlock">5c</td>
<td class="VBlock">Mi 5.</td>
<td class="VBlock">xxxxx / D</td>
<td class="VBlock">xxxxx</td>
<td class="VBlock">Vertr.</td>
<td class="VBlock">210</td>
<td class="VBlock" style="white-space:normal">Raum�nderung</td>
</tr>
<tr class="normal">
<td class="VBlock">5c</td>
<td class="VBlock">Mi 6.</td>
<td class="VBlock">xxxxx / PSD</td>
<td class="VBlock">entf�llt</td>
<td class="VBlock"></td>
<td class="VBlock"></td>
<td class="VBlock" style="white-space:normal"></td>
</tr>
und mit ausnahmen:
Code: Alles auswählen
<tr class="normal Leselinie">
<td class="VBlock">5c</td>
<td class="VBlock">Mi 8.</td>
<td class="VBlock">xxxxx / E</td>
<td class="VBlock">entf�llt</td>
<td class="VBlock"></td>
<td class="VBlock"></td>
<td class="VBlock" style="white-space:normal">verlegt auf Fr 29. Mrz 6. Std.</td>
</tr>
Aber ich glaub ich brauch das gar nicht mehr..meine Ausgabe ist jetzt immer:
Code: Alles auswählen
Für dich entfällt am Mi die 4. F
Für dich entfällt am Mi die 5. D
Für dich entfällt am Mi die 6. D
Für dich entfällt am Do die 4. Ch
Soweit passt das auch..mein code:
Code: Alles auswählen
stundenplan = []
for absatz in absaetze:
eintrag = absatz.text.split() # TODO: besseres Aufbereiten der Einträge
stundenplan.append(eintrag)
with open('csvfile.csv', 'a', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter='|')
writer.writerows(stundenplan)
# oder '6d'
for eintrag in stundenplan:
if eintrag[0] == klasse:
tag = eintrag[1]
stunde = eintrag[2]
fach = eintrag[5]
print("Für dich entfällt am ", tag, "die ", stunde, fach)
So bin ich schonmal zufrieden..nur will ich natürlich nicht schreiben, wenn eine raumänderung war, dass irgendwas entfällt. ich dachte mir, dass ich das einfach mit einem if machen könnte:
Code: Alles auswählen
for eintrag in stundenplan:
if eintrag[0] == klasse:
tag = eintrag[1]
stunde = eintrag[2]
fach = eintrag[5]
if eintrag[6] == "entf�llt":
print("Für dich entfällt am ", tag, "die ", stunde, fach)
elif eintrag[6] == "Raum�nderung":
print("Raumänderung")
tja..so gehts wohl nicht..ich schätze es ist wegen der falschen Kodierung des ä
kann man das irgendwie ganz einfach festlegen, wie die csv-Datei kodiert werden soll und wie sie abgerufen wird?
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 11:48
von Sirius3
Wie hast Du denn jetzt das HTML gelesen? Diesen Teil des Codes verschweigst Du noch immer. Dort liegt der Fehler, dass Du die Spalten der Tabelle alle zusammenwirfst und dort liegt wahrscheinlich auch der Fehler mit dem Encoding.
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 11:55
von vertretung
Ich zeig dir einfach alles was ich bisher hab..
Code: Alles auswählen
import requests
from bs4 import BeautifulSoup
import csv
URL = "http://vertretungsplan.jkg-reutlingen.de/Vertretungen-Sa.html"
r = requests.get(URL)
# htmlcode = r.text #das ist eigentlich das normale was ich aktiv machen würde, aber da die website gerade nichts anzeigt, greif ich mit htmlcode=open(...)auf den code zu den ich mir mal rauskopiert habe
htmlcode = open("sourcecode.txt", "r").read()
print("Wähle deine Stufe.")
stufe = input()
print("Wähle deine Klasse.")
klassenbuchstabe = input()
klasse = stufe+klassenbuchstabe
print("Deine Klasse ist: "+klasse)
ent = "entfällt"
soup = BeautifulSoup(htmlcode, 'html.parser')
absaetze = soup.find_all('tr')
stundenplan = []
for absatz in absaetze:
eintrag = absatz.text.split()
stundenplan.append(eintrag)
with open('csvfile.csv', 'a', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter='|')
writer.writerows(stundenplan)
for eintrag in stundenplan:
if eintrag[0] == klasse:
tag = eintrag[1]
stunde = eintrag[2]
fach = eintrag[5]
if eintrag[6] == "entf�llt":
print("Für dich entfällt am ", tag, "die ", stunde, fach)
elif eintrag[6] == "Raum�nderung":
print("Raumänderung")
Danke übrigens für deine schnellen und tollen Antworten!
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 12:22
von Sirius3
Beim Lesen aus der Text-Datei mußt Du natürlich das selbe Encoding benutzen, wie beim Schreiben, also wahrscheinlich das der ursprünglichen HTML-Seite, also `ISO-8859-1`.
Code: Alles auswählen
with open("sourcecode.txt", encoding='ISO-8859-1') as source:
htmlcode = source.read()
Zum Parsen der Tabelle, nutze BeautifulSoup:
Code: Alles auswählen
vertretungsplan = []
for row in vertretungsplan.find_all('tr'):
vertretungsplan.append([c.text for c in row.find_all('td')])
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 12:34
von vertretung
Sirius3 hat geschrieben: Montag 12. August 2019, 12:22
Beim Lesen aus der Text-Datei mußt Du natürlich das selbe Encoding benutzen, wie beim Schreiben, also wahrscheinlich das der ursprünglichen HTML-Seite, also `ISO-8859-1`.
Code: Alles auswählen
with open("sourcecode.txt", encoding='ISO-8859-1') as source:
htmlcode = source.read()
Zum Parsen der Tabelle, nutze BeautifulSoup:
Code: Alles auswählen
vertretungsplan = []
for row in vertretungsplan.find_all('tr'):
vertretungsplan.append([c.text for c in row.find_all('td')])
Soweit so gut, aber ich bekomm edn Error:
Code: Alles auswählen
for row in vertretungsplan.find_all('tr'):
AttributeError: 'list' object has no attribute 'find_all'
Kann ich da nicht anstelle von find_all filter nehmen?
EDIT:
ne kann ich nicht..gleicher Error, aber wieso? Ich dachte filter wäre eine methode von einer liste
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 12:46
von Sirius3
Muß ja an der Stelle auch `htmlcode´ statt `vertretungsplan` heißen.
Re: csv-Liste auslesen und ausgeben
Verfasst: Montag 12. August 2019, 12:49
von vertretung
Code: Alles auswählen
for row in htmlcode.find_all('tr'):
AttributeError: 'list' object has no attribute 'find_all'
...also entweder steh ich vollkommen auf dem Schlauch oder es geht echt nicht