xls-Datei in csv-Datei umwandeln

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

Ich habe das Problem, eine Excel-Datei (xls) in eine csv-Datei umzuwandeln.
Habe lange gegoogelt, um eine Lösung dafür zu finden, aber irgendwie funktioniert es einfach nicht.

Hier habe ich mal meinen aktuellen Code:

Code: Alles auswählen

def xls2csv(xls, out_file):
    with xlrd.open_workbook(xls) as wb:
        sh = wb.sheet_by_index(0)  # or wb.sheet_by_name('name_of_the_sheet_here')
        with open(out_file, 'wb') as f:
            c = csv.writer(f)
            for r in range(sh.nrows):
                c.writerow(sh.row_values(r))
Als Fehlermeldung, erhalte ich:
TypeError: 'str' does not support the buffer interface
Diese Fehlermeldung, bezieht sich auf die letzte Zeile,

Hoffe, Ihr könnt mir dabei helfen!

Grüße Nobuddy
BlackJack

@Nobuddy: Wo kommt die Ausnahme (Traceback) und welche Python-Version? Ich rate mal und es ist Python 3 und Du bekommst Unicode-Zeichenketten von der XLS-Datei und musst die kodieren bevor Du sie in die Binärdatei schreiben kannst.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo BlackJack,

Python3 ist richtig und Deine zweite Vermutung könnte zutreffen.
Wie und Wo setze ich die Codierung an?
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Dank Deines Denkanstoßes, habe ich die Lösung gefunden. :wink:

Code: Alles auswählen

    def xls2csv(xls, out_file):
        with xlrd.open_workbook(xls) as wb:
            sh = wb.sheet_by_index(0)  # or wb.sheet_by_name('name_of_the_sheet_here')
            with codecs.open(out_file, 'wb', 'utf-8') as zielfile:
                rows = []
                for r in range(sh.nrows):
                     rows.append(sh.row_values(r))
                writer = csv.writer(zielfile, delimiter="\t", quotechar='^')
                writer.writerows(rows)
Grüße Nobuddy
Sirius3
User
Beiträge: 17762
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: der quotechar ist ein bißchen exotisch.

Warum jetzt den Umweg über die Liste?

Code: Alles auswählen

with xlrd.open_workbook(xls) as wb:
            sh = wb.sheet_by_index(0)
    with codecs.open(out_file, 'wb', 'utf-8') as zielfile:
        writer = csv.writer(zielfile, delimiter="\t", quotechar='^')
        writer.writerows(sh.row_values(r) for r in range(sh.nrows))
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo Sirius3,

wenn es noch einfacher geht, vielleicht kannst Du mir zeigen wie?
Was ich noch nicht hin bekommen habe, ist wenn ein header vorhanden ist, diesen nicht mit in die csv-Datei zu übernehmen.
Vielleicht hast Du mir dazu auch einen Tip?

Grüße Nobuddy
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo Sirius3,

habe wohl Deinen Code nicht registriert, sorry!

Code: Alles auswählen

    header = 0   # Wenn Header vorhanden, sonst 'header = ''
    with xlrd.open_workbook(xls) as wb:
                sh = wb.sheet_by_index(0)
        with codecs.open(out_file, 'wb', 'utf-8') as zielfile:
            writer = csv.writer(zielfile, delimiter="\t", quotechar='^')
            writer.writerows(sh.row_values(i)
                        for i in range(sh.nrows) if i != header)
header, habe ich hier nur zur Nachvollziehung erstellt, dieser ist sonst bei mir an anderer Stelle hinterlegt.
Schön wäre es natürlich, wenn es in xlrd eine Funktion gäben würde, die einen Header erkennt, wenn er vorhanden ist.

Grüße Nobuddy
Sirius3
User
Beiträge: 17762
Registriert: Sonntag 21. Oktober 2012, 17:20

@Nobuddy: woran erkennst Du, was ein Header ist? Wenn Du weißt, dass in der ersten Zeile immer ein Header ist, kannst du einfach mit der zweiten anfangen.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@Sirius3, klar wenn es einen Header gibt, ist er immer in der ersten Zeile.
Das Problem ist, dass nicht alle xls- und csv-Dateien einen Header haben.
Wenn kein Header vorhanden ist, gibt es immer eine Datei in der, der Aufbau der Tabelle beschrieben ist.
Bisher habe ich immer, mir die Original-Datei angeschaut und wenn ein Header in Zeile 1 war, habe ich das in meiner Listen-Dokumentation beschrieben. Ich führe für alle xls- uns csv-Dateien eine Dokumentation, die vom Download (HTTP, FTP), der Codierung, den Spalten usw. beschrieben sind. Auf diese Dokumentation, greife ich dann zu, wenn ich bestimmte Informationen benötige.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Finde ich interessant, was Du da machst. Excel ist aber so gar nicht meins.

Hast Du mal geschaut, wie die Spaltenköpfe bei Dir aussehen, ob es in den Zeilen z. B. bestimmte Auffälligkeiten gibt, also "ID" oder Hinweise auf Maßeinheiten, Währungen in Klammern o. ä. Falls ja, dann würde ich versuchen die Prüfung, ob ein Header enthalten ist, dynamisch zu implementieren.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo pixewakb,

die Spaltenköpfe lassen sich so nicht identifizieren, da dies von Tabelle zu Tabelle unterschiedlich ist.
Ich weiss zwar, daß die Spaltenköpfe der Dateien immer gleich sind, aber zwischen den verschiedenen Dateien, gibt es kein einheitliches Spalten-Format. Daher bleibt mir momentan nur eins, dies in meiner Dokumentation zu hinterlegen.
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Überleg Dir - das wollte ich sagen - ob es bestimmte Inhalte gibt, die nur in den Spaltenköpfen vorkommen können. Dann kannst Du danach schauen. Ferner gibt es vielleicht auch Werte, die dort niemals stehen können, z. B. Gleitkommazahlen. Persönlich würde ich so etwas immer gern automatisieren wollen.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Das Automatisieren, ist ja mein Ziel, daher suche ich in xlrd eine Möglichkeit, dies zu erreichen. :wink:
Sirius3
User
Beiträge: 17762
Registriert: Sonntag 21. Oktober 2012, 17:20

1. ist Zelle A1 Zahl
2. wenn ja -> kein Header
3. wenn nein -> 1. Zeile Header
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@Sirius3, so einfach ist das nicht.
Z.B.:
A1 = 'Artikel'
A2 = '12345X'
ODER
A1 = 'Hauptgruppe'
A2 = 'Kopierpapier'

Wie schon mal erwähnt, sind die Tabellen-Formate, nach Bezug sehr unterschiedlich.
Sirius3
User
Beiträge: 17762
Registriert: Sonntag 21. Oktober 2012, 17:20

Jetzt hast Du zwei Beispiele mit zwei unterschiedlichen Headern und völlig unterschiedlichen Spaltenbedeutungen. Wie viele unterschiedliche Tabellenformate hast Du denn? Willst Du die alle in die selbe Form bringen?
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Ich würde das irgendwann hart in den Quelltext codieren und zwar sichere Spaltenköpfe, wie z. B. "Artikel" oder "Hauptgruppe" in einer Liste einfach bereitstellen.

Code: Alles auswählen

header = ["ID", "Was anderes", "Was ganz anderes", 'Artikel', '12345X']
spaltenkoepfe = ["Artikel", "Hauptgruppe"]
kopfzeile = False

for item in header:

    if item in spaltenkoepfe:

        kopfzeile = True
        print("Erste Zeile ist ein Spaltenkopf!")
        break
Das ist ein ganz einfaches Beispiel, erweitern könnte man das Beispiel z. B. indem man mal den ganzen Datensatz durchsucht, ob nach der ersten Zeile der Treffer noch irgendwo auftauchte. Das wäre dann entweder ein Hinweis dafür, dass der Datensatz beschädigt ist oder aber ein Hinweis dafür, dass du einen falsch negativen Treffer hattest und daher der Spaltenkopf als Unterscheidungskriterium nicht geeignet ist. Ich denke nicht, dass andere Herangehensweisen für Dich Sinn machen. Die obige Lösung ist vielleicht nicht elegant, könnte sich aber auszahlen. Wenn man wüsste womit Du sonst noch so zu tun hast, könnte man vielleicht elegantere Lösungen finden.

BTW: Der Quellcode dient nur zur Demonstration, um die Idee zu verdeutlichen. Das ist nicht schön geschrieben...

Hinweis von sirius3 gelesen...
Zuletzt geändert von pixewakb am Dienstag 6. Oktober 2015, 22:40, insgesamt 2-mal geändert.
Sirius3
User
Beiträge: 17762
Registriert: Sonntag 21. Oktober 2012, 17:20

@pixewakb: das ist nicht nur nicht schön, sondern ausgesprochener Quatsch. Hast Du Dir schonmal überlegt, wann die if-Bedingung erfüllt ist?
Benutzeravatar
pixewakb
User
Beiträge: 1412
Registriert: Sonntag 24. April 2011, 19:43

Danke, ich habe es korrigiert. Ich hatte das gerade sehr zügig zusammengetippt. Ich bin mir unsicher, ob der Fragesteller noch am Thema interessiert ist, in diesem Fall könnte der Code - schlecht geschrieben - vielleicht ein Impuls sein, das Thema von einer anderen Seite noch mal anzugehen.
Antworten