Seite 1 von 2

Daten aus Excel auslesen

Verfasst: Mittwoch 1. Juni 2005, 12:35
von Corny
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

Verfasst: Mittwoch 1. Juni 2005, 13:03
von CM
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

Re: Daten aus Excel auslesen

Verfasst: Mittwoch 1. Juni 2005, 15:22
von gerold
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
:-)

Re: Daten aus Excel auslesen

Verfasst: Mittwoch 1. Juni 2005, 16:08
von Joghurt
gerold hat geschrieben:

Code: Alles auswählen

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

*SCNR*

Verfasst: Donnerstag 2. Juni 2005, 08:21
von Corny
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

Verfasst: Donnerstag 2. Juni 2005, 20:00
von CM
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

Verfasst: Freitag 3. Juni 2005, 07:19
von Corny
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)

Verfasst: Mittwoch 16. August 2006, 11:25
von eiwolf
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

Verfasst: Mittwoch 16. August 2006, 12:29
von birkenfeld
Zum Auslesen von Excel-Dateien gibt es
* pyexcelerator
* xlrd
(Google sollte Links ausspucken).

Verfasst: Mittwoch 16. August 2006, 12:42
von 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.

Verfasst: Mittwoch 16. August 2006, 14:02
von eiwolf

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

Verfasst: Mittwoch 16. August 2006, 15:13
von 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.

Verfasst: Mittwoch 16. August 2006, 15:37
von eiwolf

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

Verfasst: Mittwoch 16. August 2006, 17:45
von 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?

Verfasst: Mittwoch 16. August 2006, 20:31
von eiwolf
ja sobald ein umlaut enthalten ist, ist es ein Zellenobjekt oder so? Solange kein umlaut enthalten ist funzt es problemlos.

Verfasst: Mittwoch 16. August 2006, 21:20
von 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.

Verfasst: Donnerstag 17. August 2006, 08:36
von eiwolf
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

Verfasst: Donnerstag 17. August 2006, 09:26
von 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.

Verfasst: Donnerstag 17. August 2006, 10:27
von eiwolf
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.

Verfasst: Donnerstag 17. August 2006, 10:50
von N317V
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.