UnicodeEncodeError

Installation und Anwendung von Datenbankschnittstellen wie SQLite, PostgreSQL, MariaDB/MySQL, der DB-API 2.0 und sonstigen Datenbanksystemen.
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

hallo allerseits,

bin python-beginner. habe gerade ein script geschrieben welches sich simple zu eine Oracle DB verbindet, eine
SQL abfrage tätigt und das ergebnis anschließend in eine CSV schreibt. klappt alles wunderbar bis auf diesen fehler (darum schreibt er die spalte auch nicht ins CSV):

"UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 43: ordinal not in range(128)"

habe mich jetzt schon einige stunden mit Decode und Encode beschäftigt, mit UTF und was weiss ich was, aber nicht wirklich eine lösung gefunden wie er mir die abfrage vervollständigt...

hier das skript, vielleicht kann mir jemand als einsteiger ein paar tipps geben:

import cx_Oracle, csv
connection = cx_Oracle.connect("usr/pw@server/instance")
cursor = connection.cursor()
cursor.execute("SELECT foo FROM bar")
writer = csv.writer(open("file.csv","wb"))
writer.writerow(["eins","zwei","drei"])
writer.writerows(cursor)
cursor.close()
connection.close()

wäre für jeden tipp dankbar, vielen herzlichen dank

achja: python 2.5 / oracle 11g

infos zu DB:

NLS_CHARACTERSET = AL16UTF16
NLS_LANGUAGE = GERMAN
deets

Bitte setzt deinen Code in python-tags, damit man ihn lesen kann. Zweitens poste bitte *mindestens* die Zeile, in welcher der Fehler passiert, natuerlich in Bezug auf das gepostete Snippet.

Ansonsten wuerde ich mal vermuten, dass du unicode Objekte von deinem Adapter bekommst, und versuchst die in eine Datei zu schreiben. Das geht natuerlich nicht ohne explizites encoding. Eine Moeglichkeit waere, aus dem Modul codecs einen writer fuer UTF-8 zu holen, und dass ungefaehr sowas zu machen:

Code: Alles auswählen

import codecs

outf = codecs.writer("utf-8")(open("file.csv", "wb"))
writer = csv.writer(outf)

...

enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

hallo, danke für die antwort und entschuldigung für meinen unleserlichen code

Code: Alles auswählen

import cx_Oracle, csv
connection = cx_Oracle.connect("usr/pw@server/instance")
cursor = connection.cursor()
cursor.execute("SELECT foo FROM bar")
writer = csv.writer(open("file.csv","wb"))
writer.writerow(["eins","zwei","drei"])
writer.writerows(cursor)
cursor.close()
connection.close()
Traceback (most recent call last):
File "C:\abfrage.py", line 21, in <module>
writer.writerows(cursor)
UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 43: ordinal not in range(128)

hab mal mit python 3.2 getestet, da kommt die fehlermeldung nicht, allerdings schreib er mir auch nichts in meine CSV;)
wenn ichs im interpreter reingebe bekomme ich eh alle ergenisse...logischerweise als "\xf6" und nicht als "ö"...
wie baue ich am besten deine möglichkeit ein?
danke nochmal und sorry für die unannehmlichkeiten
deets

Na, genau so wie ich sie geschrieben habe, das ersetzt dir doch exakt deine Code wie du den CSV-writer baust. Und du hast auch immer noch nicht erzaehlt, in welcher Zeile genau der Fehler passiert.
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

ja sorry, wie gesagt, hab bis vorgestern noch nicht viel ahnung von python gehabt...insofern bitte ich um rücksichtnahmen was das alles angeht...

wenn ich den code dann so ändere

Code: Alles auswählen

	
import codecs, cx_Oracle, csv
connection = cx_Oracle.connect("usr/pw@server/instance")
cursor = connection.cursor()
cursor.execute("SELECT foo FROM bar")
outf = codecs.writer("utf-8")(open("file.csv", "wb"))
writer = csv.writer(outf)
writer.writerows(cursor)
cursor.close()
connection.close()
dann gibts den fehler:

Traceback (most recent call last):
File "C:/abfrage", line 13, in <module>
outf = codecs.writer("utf-8")(open("C:/file.csv","w"))
AttributeError: 'module' object has no attribute 'writer'


und wo bitte schau ich nach in welcher zeile mein fehler passiert?? ja sorry, lacht mich aus, aber kein meister ist vom himmel gefallen...
ich lass das skript im interpreter laufen, da zeigt er mir nur den geposteten fehler an(soweit ich das seh)...

ich bedanke mich nochmals
Benutzeravatar
/me
User
Beiträge: 3561
Registriert: Donnerstag 25. Juni 2009, 14:40
Wohnort: Bonn

enrico83 hat geschrieben:Traceback (most recent call last):
File "C:/abfrage", line 13, in <module>
outf = codecs.writer("utf-8")(open("C:/file.csv","w"))
AttributeError: 'module' object has no attribute 'writer'


und wo bitte schau ich nach in welcher zeile mein fehler passiert?? ja sorry, lacht mich aus, aber kein meister ist vom himmel gefallen...
Wo der Fehler passiert ist steht in der Fehlermeldung: line 13.

Verwende mal codecs.getwriter statt codecs.writer.
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

wenn ich es so mache:

Code: Alles auswählen

import codecs, cx_Oracle, csv
connection = cx_Oracle.connect("us/pw@server")
cursor = connection.cursor()
cursor.execute("SELECT foo FROM bar")
outf = codecs.getwriter("utf-8")(open("C:/file.csv", "w"))
writer = csv.getwriter(outf)
writer.writerows(cursor)
cursor.close()
connection.close()
kommt das selbe:

Traceback (most recent call last):
File "C:/Python32/test3_2.py", line 6, in <module>
writer = csv.getwriter(outf)
AttributeError: 'module' object has no attribute 'getwriter'

hab das ganze mit version 3.2.1 durchgeführt! mit 2.5 gibt er mir immer noch den alten fehler "
(UnicodeEncodeError: 'ascii' codec can't encode character u'\xf6' in position 43: ordinal not in range(128))
oder hab ich das modul falsch eingefügt im code? bzw. wenn ich nur

Code: Alles auswählen

outf = codecs.writer("utf-8")(open("C:/file.csv", "w"))
mit

Code: Alles auswählen

outf = codecs.getwriter("utf-8")(open("C:/file.csv", "w"))
ersetz gibts das

Traceback (most recent call last):
File "C:/Python32/test3_2.py", line 7, in <module>
writer.writerows(cursor)
File "C:\Python32\lib\codecs.py", line 356, in write
self.stream.write(data)
TypeError: must be str, not bytes

sorry, aber ich muss mir die syntax erst eingewöhnen


gibts weitere ideen :(?
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

hat jemand noch ideen? komm einfach nicht weiter
deets

Gib doch mal bitte aus, was eigentilch aus der Datenbank rauskommt. Das modul pprint hilft dir dabei. Und zeige uns das.
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

also als ergebnis erhalte ich in meiner csv alle records ohne umlaute:

503799,Name Name,None,2984 02
810287,Name Name,None,2984 02
379748,Name Name,None,2984 02
640938,Name Name,None,2984 02
581775,Name Name,None,2984 02

id, name (eben manche mit umlaute), firmeninterne nummer..das wärs eigentlich

mittlerweile sieht der code so aus:

Code: Alles auswählen

import codecs, cx_Oracle, csv
connection = cx_Oracle.connect("usr/pw@server/instance")
cursor = connection.cursor()
cursor.execute("SELECT foo From bar)
outf = codecs.open("C:/result.csv", "wb", encoding="utf-8")
writer = csv.writer(outf)
writer.writerows([[f.encode("utf-8") if type(f) is unicode else str(f) for f in r] for r in cursor])
cursor.close()
connection.close()
error:

Code: Alles auswählen

Traceback (most recent call last):
  File "C:\abfrage.py", line 7, in <module>
    writer.writerows([[f.encode("utf-8") if type(f) is unicode else str(f) for f in r] for r in cursor])
  File "C:\PROGRA~1\Python25\Lib\codecs.py", line 638, in write
    return self.writer.write(data)
  File "C:\PROGRA~1\Python25\Lib\codecs.py", line 303, in write
    data, consumed = self.encode(object, self.errors)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 50: ordinal not in range(128)

aber ich steh an...

es kann von mir auch ein excel-sheet sein, solang das mit den umlauten bzw. encodierung klappt
deets

Das ist nicht das, worum ich gebeten hatte. Ich moechte wirklich die genau repraesentation sehen, eine Ausgabe der Datenstrukturen mittels pprint. Und natuerlich auch und gerade dann, wenn Umlaute in den Daten sind!

Ausserdem bitte entweder entscheiden oder immer dazu angeben, welche Version von Python du benutzt (es waren ja 2.5 und 3.2 im Spiel), denn das ist gerade in diesem Bereich ein himmelweiter Unterschied und muss darum klar sein.
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

bin und bleibe bei python 2.5.1...

ok danke..ich muss mich dann auch mal in das pprint einlesen um dir das gewünschte zu liefern...ich hoffe das dauert nicht allzulange

im interpreter erscheinen ja alle ergebnisse mit print (halt nicht codiert als umlaute)
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

du hast eine pn;)
deets

Ok, nochmal fuer die Oeffentlichkeit: die Datenbank liefert tatsaechlich unicode-Objekte zurueck, als Liste von Tupeln. So etwa:

Code: Alles auswählen

[
(1111111,
  u'\xf6',
  None,
  'irgendwas'),
]
Was dann noch fehlt ist die Angabe mit welcher Python-Version du diese Ausgabe produziert hast.
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

2.5.1
deets

Ok, ich hab' jetzt nicht mehr Zeit dafuer, aber das hier geht. Das absurde ist, dass das outf mittels codecs.open genau so funktioniert, wie man es sich erwartet - aber in dem Moment, in dem man damit versucht mit dem CSV-Wrtier zu arbeiten, geht's in die Hose. Ich habe nicht den Hauch einer Ahnung warum, vielleicht erhellt uns wer anderes.

Code: Alles auswählen

import codecs, csv, pprint
outf = codecs.open("/tmp/result.csv", "w", encoding="utf-8")
outf.write(u'\xf6\n')
outf.close()

# und nochmal binaer und ohne transparentes encoding
outf = open("/tmp/result.csv", "ab")
writer = csv.writer(outf)

rows = [
    (1111111,
     u'\xf6',
     None,
     'irgendwas'),
    ]

pprint.pprint(rows)
encoded_rows = []
for row in rows:
    encoded_rows.append(tuple(item.encode("utf-8") if isinstance(item, unicode) else item for item in row))

writer.writerows(encoded_rows)
enrico83
User
Beiträge: 13
Registriert: Dienstag 2. August 2011, 12:52

ja ich danke mal vielmals für die hilfe..vielleicht hat hier jemand die glorreiche idee wie ich die daten in mein csv bekomm oder wo der fehler liegt...aber wie gesagt es muss ja nicht das unbedingt das csv modul sein, vielleicht ginge es ja mit excel...
deets

Erm, dir ist schon klar, dass mein code oben fuer dich einfach anzupassen ist, oder? Ich habe halt keine oracle datenbank (dankenswerterweise), geschweige denn deine Daten. Ein bisschen Eigenleistung musst du schon erbringen, und den Code einbauen....
BlackJack

@deets: Der CSV-Writer will halt kein `unicode` haben. Dem muss man `str` geben. Und damit braucht man dann kein `codecs.open()` mehr. Denn das will `unicode`, der CSV-Writer gibt aber `str` an das `file`-like weiter.
deets

@BlackJack: soweit, klar. Was mich wundert ist eben dieses beharren darauf. Was kuemmert's ihn? Einen Grund in technischer Hinsicht kann ich nicht sehen. Aber ist dann halt nen Implementationsartefakt.
Antworten