Daten aus Excel auslesen

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.
Corny
User
Beiträge: 15
Registriert: Dienstag 11. Januar 2005, 10:48
Wohnort: München

Hi,

ich bins mal wieder.

Ich habe im Script mithilfe des pyXLWriter eine Excel-Tabelle erstellt, in die ich bestimmte Ergebnisse speichern kann. Das passt auch schon alles wunderbar. Nur wie kann ich wieder den Inhalt einer bestimmten Zelle auslesen?

Grüße
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Hi Corny,

puh, ich glaube ich muß Dich enttäuschen: pyXLWriter kann das nicht. Der pyXLWriter schreibt nur in Excel-Spreadsheets aus (und das auch nicht auf dem neuesten Stand), kann aber nicht lesen.
gnumeric soll das leisten können, was Du suchst, aber das ist wohl ziemlich umständlich, wenn Du gnumeric nicht schon hast.

Ansonten kann ich vielleicht empfehlen von Excel in ASCII/CSV zu schreiben und dann Python weitermachen zu lassen. Ist zwar etwas mehr "Handarbeit", aber möglicherweise trotz alledem das Praktischte.

Ich würde mich selber auch freuen, wenn mir jemand wiedersprechen kann und eine einfache Lösung hat.

Gruß,
Christian
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Corny hat geschrieben: Nur wie kann ich wieder den Inhalt einer bestimmten Zelle auslesen?
Hi Corny!

Wenn es dich nicht stört, pywin32 zu installieren, dann kannst du so die Werte auslesen:

Code: Alles auswählen

>>> import win32com.client
>>> excel = win32com.client.Dispatch("Excel.Application")
>>> wb = excel.Workbooks.Open(Filename = r"C:\_Ablage\Mappe1.xls", ReadOnly = True)
>>> ws = wb.Sheets("Tabelle1")
>>> print ws.Range("A1")
hallo
>>> del ws
>>> del wb
>>> del excel
>>> 
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

gerold hat geschrieben:

Code: Alles auswählen

del excel
Also, der Befehl gefällt mir :mrgreen:

*SCNR*
Corny
User
Beiträge: 15
Registriert: Dienstag 11. Januar 2005, 10:48
Wohnort: München

Danke für die Antworten. Na OK, vom pyXLwriter kann man wahrscheinlich das auch nicht verlangen ;o)

Ich wollte in das Excelfile nur in eine bestimmte Zeile einen Counter einfügen damit ich bei einem späteren Lauf auf diesen zurückgreifen kann, aber wenn das nicht so "auf die Schnelle" geht dann lege ich eben da im Verzeichnis einfach eine Counterdatei extra an. Schön sein muss es ja zum Glück nicht, nur funktionieren sollte es :)

Weitere Werte muss ich nicht mehr auslesen; das Excelfile soll lediglich als Protokoll Fehler während der Programmläufe komfortabel und übersichtlich anzeigen.

Ach und wenn ich schon mal hier bin :): Wie kann ich einen Link auf eine Datei in eine Excel-Zelle einfügen?

Grüße
CM
User
Beiträge: 2464
Registriert: Sonntag 29. August 2004, 19:47
Kontaktdaten:

Mit dem pyXLWriter mit dem 'external' Schlüsselwort.
z.B.:

Code: Alles auswählen

worksheet.write(cell,"external:path")
#konkreter
worsheet.write(cell,"external:./test.dat")
Aber das hat nur sehr eingeschränkte Funktionalität und liest bei mir (Excel:mac) auch keine Daten in das Spreadsheet ein, sondern man kann so nur die externe Datei von Excel aus öffnen. Am besten mal ausprobieren - aber ich befürchte, diese Funktionalität gibt Dir nicht, was Du suchst.

Tut mir leid, damit bin ich mit meinem Latein am Ende. Aber Du hast jetzt ja eine mögliche Alternativlösung für jedes Betriebssystem. Wobei mir Gerolds Lösung für den Fall, daß Du ein Windows benutzt am besten erscheint.

Gruß,
Christian
Corny
User
Beiträge: 15
Registriert: Dienstag 11. Januar 2005, 10:48
Wohnort: München

CM hat geschrieben:Mit dem pyXLWriter mit dem 'external' Schlüsselwort.
z.B.:

Code: Alles auswählen

worksheet.write(cell,"external:path")
#konkreter
worsheet.write(cell,"external:./test.dat")
Danke, genau das habe ich gesucht.

Mit der Extra-Zählerdatei klappt das gut - wenn zwar auch nicht sonderlich hübsch, aber es geht im Endeffekt ja doch nur um das Excel-File was erstellt wird. Ich möchte ungern noch mehr Zeugs installieren da ich das alles noch auf mindestens 2 Rechnern abbilden muss - da ist weniger oft mehr ;o)
eiwolf
User
Beiträge: 9
Registriert: Mittwoch 16. August 2006, 11:10

Hallo Leute,

ich möchte auch Daten aus einem Excelsheet auslesen leider bekomme ich folgenden Fehler:
Traceback (most recent call last):
File "C:\eclipse\wolfgang\Wolfgangtest\DTC_XLS_2_SGBD\DTC_XLS_2_SGBD.py", line 151, in ?
print DTCExcel.ReturnValue("D",str(88))
File "C:\Python24\Lib\site-packages\win32com\client\dynamic.py", line 187, in __str__
return str(self.__call__())
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 45: ordinal not in range(128)
Das ganze habe ich - versucht zumindest - objektorientiert gestalltet:

Code: Alles auswählen

class excel:
    def __init__(self,excelpath,Sheet):
        excel = win32com.client.Dispatch("Excel.Application")
        excel.Visible = True        
        wb = excel.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = wb.Sheets(Sheet)
         
    def ReturnValue(self,Line,Row):
        return self.ws.Range(Line+Row)
    def __del__(self):
            print "excel destructor"
Und hier der Aufruf:

Code: Alles auswählen

print DTCExcel.ReturnValue("D",str(88))
In der Exceltabelle sind Umlaute. Wenn ich diese entferne funzt es. Wie kann ich aber trotzdem Umlaute exportieren?

2. Frage:

Wenn ich das Objekt lösche, will ich auch Excel und die Exceldatei beenden. Ich habe das ganze in der Klasse excel unter __del__ geschrieben:

Code: Alles auswählen

class excel:
    def __init__(self,excelpath,Sheet):
        excel = win32com.client.Dispatch("Excel.Application")
        excel.Visible = True        
        wb = excel.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = wb.Sheets(Sheet)
         
    def ReturnValue(self,Line,Row):
        return self.ws.Range(Line+Row)
    def __del__(self):
            del excel
            print "excel destructor"



Dann kommt der Fehler:
Exception exceptions.UnboundLocalError: "local variable 'excel' referenced before assignment" in <bound method excel.__del__ of <__main__.excel instance at 0x00B6D5D0>> ignored
Was mache ich falsch?


Danke für euere Hilfe.

MFG
Wolfgang
Benutzeravatar
birkenfeld
Python-Forum Veteran
Beiträge: 1603
Registriert: Montag 20. März 2006, 15:29
Wohnort: Die aufstrebende Universitätsstadt bei München

Zum Auslesen von Excel-Dateien gibt es
* pyexcelerator
* xlrd
(Google sollte Links ausspucken).
BlackJack

eiwolf hat geschrieben:Hallo Leute,

ich möchte auch Daten aus einem Excelsheet auslesen leider bekomme ich folgenden Fehler:
Traceback (most recent call last):
File "C:\eclipse\wolfgang\Wolfgangtest\DTC_XLS_2_SGBD\DTC_XLS_2_SGBD.py", line 151, in ?
print DTCExcel.ReturnValue("D",str(88))
File "C:\Python24\Lib\site-packages\win32com\client\dynamic.py", line 187, in __str__
return str(self.__call__())
UnicodeEncodeError: 'ascii' codec can't encode character u'\xe4' in position 45: ordinal not in range(128)
Umlaute lassen sich nicht in ASCII darstellen. ``print`` denkt das `sys.stdout` nur ASCII "versteht" und versucht die Zeichenkette entsprechend zu kodieren.

Schau mal hier weiter: http://www.python-forum.de/topic-2294.html

Wenn das ``print`` nur zum Fehlersuchen da ist, dann kannst Du das was ausgegeben werden soll mit `repr()` in etwas umwandeln was nur ASCII Zeichen enthält.
Das ganze habe ich - versucht zumindest - objektorientiert gestalltet:

Code: Alles auswählen

class excel:
    def __init__(self,excelpath,Sheet):
        excel = win32com.client.Dispatch("Excel.Application")
        excel.Visible = True        
        wb = excel.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = wb.Sheets(Sheet)
         
    def ReturnValue(self,Line,Row):
        return self.ws.Range(Line+Row)
    def __del__(self):
            print "excel destructor"
Wenn Du das `excel` Objekt später noch brauchst, dann solltest Du es auch an das `excel` Objekt binden. ;-) Und die Klasse sollte besser `Excel` heissen, schon alleine um den vorherigen Satz eindeutiger zu machen. :-)
Und hier der Aufruf:

Code: Alles auswählen

print DTCExcel.ReturnValue("D",str(88))
Warum ``str(88)`` und nicht einfach nur '88'?
In der Exceltabelle sind Umlaute. Wenn ich diese entferne funzt es. Wie kann ich aber trotzdem Umlaute exportieren?
Exportieren wohin? Immer wenn etwas ausserhalb von ASCII vorkommt, musst Du Dich mit Kodierungen auseinandersetzen.
2. Frage:

Wenn ich das Objekt lösche, will ich auch Excel und die Exceldatei beenden. Ich habe das ganze in der Klasse excel unter __del__ geschrieben:
Keine gute Idee. Für den Aufruf von `__del__()` werden in der Spezifikation wenig Garantien gegeben. Eine explizite `close()` Methode die Du aufrufst wenn Du fertig bist, ist sicherer und sauberer.

Code: Alles auswählen

class excel:
    def __init__(self,excelpath,Sheet):
        excel = win32com.client.Dispatch("Excel.Application")
        excel.Visible = True        
        wb = excel.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = wb.Sheets(Sheet)
         
    def ReturnValue(self,Line,Row):
        return self.ws.Range(Line+Row)
    def __del__(self):
            del excel
            print "excel destructor"
Dann kommt der Fehler:
Exception exceptions.UnboundLocalError: "local variable 'excel' referenced before assignment" in <bound method excel.__del__ of <__main__.excel instance at 0x00B6D5D0>> ignored
Was mache ich falsch?
Du benutzt einen Namen in einer Funktion bevor Du ihn an etwas gebunden hast. Wenn Du nicht einen lokalen Namen `excel` haben wolltest, sondern den auf Modulebene hättest Du das mit ``global excel`` in der Funktion bekannt machen müssen. Damit entfernst Du dann aber die die Bindung zur `excel` *Klasse* im Modul. Sicher nicht das was Du wolltest.
eiwolf
User
Beiträge: 9
Registriert: Mittwoch 16. August 2006, 11:10

Code: Alles auswählen

class Excel:
    def __init__(self,excelpath,Sheet):
        excelobj = win32com.client.Dispatch("Excel.Application")
        excelobj.Visible = True        
        wb = excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = wb.Sheets(Sheet)
         
    def ReturnValue(self,Line,Row):
        test = u""
        test = self.ws.Range(Line+Row)
        return test
    def __del__(self):
            print "excel destructor"
Wenn Du das `excel` Objekt später noch brauchst, dann solltest Du es auch an das `excel` Objekt binden. Wink Und die Klasse sollte besser `Excel` heissen, schon alleine um den vorherigen Satz eindeutiger zu machen.
>> Stimmt :oops: - ist mir noch garnicht aufgefallen Danke. Trotzdem kann ich mit deiner Aussage leider nichts anfangen.

Code: Alles auswählen


print DTCExcel.ReturnValue("D",str(88))
Ich hab das ganze ohne str ( 88 ) versucht - kommt aber leider fehlermeldung das man str mit int nicht ??? kann - und so gehts
Exportieren wohin? Immer wenn etwas ausserhalb von ASCII vorkommt, musst Du Dich mit Kodierungen auseinandersetzen.
In eine Textdatei will ich es exportieren. Dazu auch ein Objekt:

Code: Alles auswählen

class textwrite:
    def __init__(self,SGBDPath):
        self.textfile = file(SGBDPath, "w")
        
    def Append(self,String):
        self.textfile.write(String)
.......
Die konsolenausgabe ist nicht notwendig... Geht das ganze dann irgendwie einfacher?

Die close() Methode wird dann aufgerufen, sobald das objekt gelöscht wird - sehe ich das richtig?
Was ist dann __del__?

Danke für euere Hilfe
BlackJack

eiwolf hat geschrieben:

Code: Alles auswählen

class Excel:
    def __init__(self,excelpath,Sheet):
        excelobj = win32com.client.Dispatch("Excel.Application")
        excelobj.Visible = True        
        wb = excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = wb.Sheets(Sheet)
         
    def ReturnValue(self,Line,Row):
        test = u""
        test = self.ws.Range(Line+Row)
        return test
    def __del__(self):
            print "excel destructor"
Wenn Du das `excel` Objekt später noch brauchst, dann solltest Du es auch an das `excel` Objekt binden. Wink Und die Klasse sollte besser `Excel` heissen, schon alleine um den vorherigen Satz eindeutiger zu machen.
>> Stimmt :oops: - ist mir noch garnicht aufgefallen Danke. Trotzdem kann ich mit deiner Aussage leider nichts anfangen.
In der `__init__()` erzeugst Du ein Objekt über das sich Excel steuern lässt und bindest es an den *lokalen* Namen `excelobj`. Dieser Name verschwindet sobald die Methode abgearbeitet ist, d.h. Du kannst da dann nicht mehr drauf zugreifen. Wenn Du es an `self.excelobj` bindest, dann kannst Du später in einer anderen Methode auch genauso wieder darauf zugreifen.

Code: Alles auswählen


print DTCExcel.ReturnValue("D",str(88))
Ich hab das ganze ohne str ( 88 ) versucht - kommt aber leider fehlermeldung das man str mit int nicht ??? kann - und so gehts
Vielleicht wurde es im Fliesstext nicht deutlich, ich meinte:

Code: Alles auswählen

print DTCExcel.ReturnValue("D", "88"))
Exportieren wohin? Immer wenn etwas ausserhalb von ASCII vorkommt, musst Du Dich mit Kodierungen auseinandersetzen.
In eine Textdatei will ich es exportieren. Dazu auch ein Objekt:

Code: Alles auswählen

class textwrite:
    def __init__(self,SGBDPath):
        self.textfile = file(SGBDPath, "w")
        
    def Append(self,String):
        self.textfile.write(String)
.......
Die konsolenausgabe ist nicht notwendig... Geht das ganze dann irgendwie einfacher?
Hm, benennst Du in der `textwrite` Klasse einfach nur die Methoden von Dateiobjekten um? Dann kannst Du auch gleich ein Dateiobjekt direkt benutzen.
Die close() Methode wird dann aufgerufen, sobald das objekt gelöscht wird - sehe ich das richtig?
Was ist dann __del__?
Nein die `close()` Methode musst *Du* aufrufen. Vergiss `__del__()` am besten komplett, das ist von der Spezifikation her genauso nutzlos wie `finalize()` in Java.
eiwolf
User
Beiträge: 9
Registriert: Mittwoch 16. August 2006, 11:10

Code: Alles auswählen

print DTCExcel.ReturnValue("D", "88"))
Ja simmt - ich hab diese Zeile nur aus einer For schleife kopiert, die normalerweise die Zeilen in dem excelsheet hochzählt
Hm, benennst Du in der `textwrite` Klasse einfach nur die Methoden von Dateiobjekten um? Dann kannst Du auch gleich ein Dateiobjekt direkt benutzen.
Stimmt auch, ich will nur aus einer EXCEL tabelle 3 textdateien füttern - deshalb dachte ich mir am anfang das das ganze in einer eigenen Klasse

sinnvoller ist.

Code: Alles auswählen

class Excel:
    def __init__(self,excelpath,Sheet):
        self.excelobj = win32com.client.Dispatch("Excel.Application")
        self.excelobj.Visible = True        
        self.wb = self.excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = self.wb.Sheets(Sheet)         
    def ReturnValue(self,Line,Row):
        return self.ws.Range(Line+Row)
    def close(self):
        del excelobj

#Oeffnet Excel Datei excel("Pfad und Dateiname mit / und nicht \!!!!,Auswahl des Sheet)
DTCExcel = Excel("....xls","All")

Zelleninhalt = DTCExcel.ReturnValue("D","88")

f = open("hallotextdatei.txt","wb")

f.write(Zelleninhalt)  # so das geht nicht


f.close()
Jetzt kommt der Fehler:
Traceback (most recent call last):
File "C:\eclipse\wolfgang\Wolfgangtest\DTC_XLS_2_SGBD\DTC_XLS_2_SGBD.py", line 167, in ?
f.write(hallo)
TypeError: argument 1 must be string or read-only buffer, not instance
Fehler ist mir klar. wenn ich das ganze aber in str() schreibe geht es wegen den umlauten auch nicht. Ich hab jetzt den ganzen Nachmittag rumgespielt wg der Textcodierung. Leider bin ich auf keinen - wirklich keinen grünen Zweig gekommen.

Versuche ich das ganze mit:

Code: Alles auswählen

hallo = DTCExcel.ReturnValue("D","88")
print hallo.encode("utf-8")
..bekomme ich diese Fehlermeldung..
Traceback (most recent call last):
File "C:\eclipse\wolfgang\Wolfgangtest\exceltest\umlaute.py", line 43, in ?
print hallo.encode("utf-8")
File "C:\Python24\Lib\site-packages\win32com\client\dynamic.py", line 496, in __getattr__
raise AttributeError, "%s.%s" % (self._username_, attr)
AttributeError: Range.encode
Danke für euere Hilfe.

MFG
Wollfgang
BlackJack

Was ist denn der Zelleninhalt für ein Typ? Offensichtlich keine Zeichenkette. Wahrscheinlich irgendwie ein "Zellenobjekt". Da gehört ja mehr dazu als der Text, oder?
eiwolf
User
Beiträge: 9
Registriert: Mittwoch 16. August 2006, 11:10

ja sobald ein umlaut enthalten ist, ist es ein Zellenobjekt oder so? Solange kein umlaut enthalten ist funzt es problemlos.
BlackJack

eiwolf hat geschrieben:ja sobald ein umlaut enthalten ist, ist es ein Zellenobjekt oder so? Solange kein umlaut enthalten ist funzt es problemlos.
Das kann ich mir kaum vorstellen. Finde besser mal heraus was es *wirklich* für ein Typ ist. Die `type()` Funktion sollte dabei helfen.
eiwolf
User
Beiträge: 9
Registriert: Mittwoch 16. August 2006, 11:10

Ich hab jetzt mal die type() funktion benutzt. In der Konsole wird "<type 'instance'>" ausgegeben.

Code: Alles auswählen

class Excel:
    def __init__(self,excelpath,Sheet):
        self.excelobj = win32com.client.Dispatch("Excel.Application")
        self.excelobj.Visible = True        
        self.wb = self.excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = self.wb.Sheets(Sheet)         
    def ReturnValue(self,Line,Row):
        print type(self.ws.Range(Line+Row)) 
        return self.ws.Range(Line+Row)
    def close(self):
        del excelobj
BlackJack

Also ist es schon mal keine Zeichenkette. Mit `obj.__class__.__name__` kannst Du herausfinden wie die Klasse heisst und mit `dir(obj)` welche Methoden es gibt.
eiwolf
User
Beiträge: 9
Registriert: Mittwoch 16. August 2006, 11:10

Super...Danke.

Auf zur nächsten Runde: Konsolenausgaben siehe komentare...

Code: Alles auswählen

class Excel:
    def __init__(self,excelpath,Sheet):
        self.excelobj = win32com.client.Dispatch("Excel.Application")
        self.excelobj.Visible = True        
        self.wb = self.excelobj.Workbooks.Open(Filename = excelpath, ReadOnly = True)
        self.ws = self.wb.Sheets(Sheet)
                 
    def ReturnValue(self,Line,Row):
        print type(self.ws.Range(Line+Row))  # <type 'instance'>
        print self.ws.__class__.__name__    #CDispatch
        print dir(self.ws)                                # siehe weiter unten
        print self.ws._unicode_to_string_      #false
        
        return self.ws.Range(Line+Row)
    def close(self):
        del excelobj
Mit dem CDispatch kann ich leider nichts anfangen....

Ausgabe von dir(self.ws):

['_ApplyTypes_', '_FlagAsMethod', '_LazyAddAttr_', '_NewEnum', '_Release_', '__AttrToID__', '__LazyMap__', '__call__', '__cmp__', '__doc__', '__getattr__', '__getitem__', '__init__', '__int__', '__len__', '__module__', '__nonzero__', '__repr__', '__setattr__', '__setitem__', '__str__', '_builtMethods_', '_enum_', '_find_dispatch_type_', '_get_good_object_', '_get_good_single_object_', '_lazydata_', '_make_method_', '_mapCachedItems_', '_oleobj_', '_olerepr_', '_print_details_', '_proc_', '_unicode_to_string_', '_username_', '_wrap_dispatch_']

kann ich leider auch nichts damit anfangen - hab auch schon die Hilfe benutzt, aber nichts brauchbares gefunden...

Danke für deine Geduld BlackJack - ich seh schon ich kann (muss) noch viel lernen.
N317V
User
Beiträge: 504
Registriert: Freitag 8. April 2005, 13:23
Wohnort: München

Soweit ich weiß gibt Range() immer ein Range-Objekt zurück. Dass man sich bei Excel nicht darauf verlassen kann, ist für mich auch keine Überraschung. :? Ich lese Werte aus einzelnen Zellen in dieser Art:

Code: Alles auswählen

self.ws.Cells(y, x).Value
Wobei ich noch eine kleine Funktion geschrieben habe, die mir die Spaltennamen in Zahlen umwandelt, denn x und y in obigem Beispiel müssen Zahlenkoordinaten sein.

HTH

edit: nochmal in der Hilfe nachgelesen, dort steht
Range-Eigenschaft, wie sie auf die Objekte Application, Range und Worksheet angewendet wird.

Gibt ein Range-Objekt zurück, das eine Zelle oder einen Zellbereich darstellt.
Es gibt für alles eine rationale Erklärung.
Außerdem gibt es eine irrationale.

Wie man Fragen richtig stellt
Antworten