UrlFetch und UnicodeDecodeError

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
Question
User
Beiträge: 2
Registriert: Freitag 24. August 2012, 19:32

Hallo,

seit gestern versuche ich eine xml-Datei aus dem Web abzurufen, das Skript soll am Ende bei GoogleAppEngine laufen.

Die Datei enthält mehrere "ö" und "ü" und fängt folgendermaßen an:

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
Mein Code zum Herunterladen sieht so aus:

Code: Alles auswählen

result = urlfetch.fetch("url")
  if result.status_code == 200:
    print "Content-type: text/plain\n\n"
    text = result.content
    print text
"text" enthält dann aber die "ö" als "ö" und die "ü" als "ü".
Wenn ich versuche die Zeichen durch ".replace("ö","ö")" zu ersetzen erhalte ich "<type 'exceptions.SyntaxError'>" zurück.

Falls ich das nicht tue sondern den Inhalt von "text" direkt weiterverwende(mit ElementTree) erhalte ich folgenden Fehler:

Code: Alles auswählen

<type 'exceptions.UnicodeEncodeError'>: 'ascii' codec can't encode character u'\xf6' in position 1: ordinal not in range(128)
      args = ('ascii', u'L\xf6we, 1, 2, 'ordinal not in range(128)') 
Ich habe es schon mit verschiedenem Encoding versucht, aber der Fehler ist immer der gleiche.

Wie kann ich die Zeichen im Text umwandeln, damit der Inhalt nachher verarbeitet werden kann?
BlackJack

@Question: `text` enthält keine "ö" als "ö" sondern `text` enthält Bytewerte bei denen "ö"s UTF-8 kodiert sind und Du sie aber mit einer anderen Kodierung dekodiert anschaust und deshalb "ö" siehst. Der erste Quelltextschnippsel sieht danach aus als wenn die Bytes an einen Browser geschickt werden. Die erwarten, solange sie nichts anderes gesagt bekommen, dass Texte als ISO-8859-1 kodiert sind. Das würde "ö" erklären, denn so sieht ein UTF-8 kodiertes "ö" aus wenn man es fälschlicherweise als ISO-8859-1 dekodiert.

Code: Alles auswählen

In [134]: a
Out[134]: '\xc3\xb6'

In [135]: print a.decode('UTF-8')
ö

In [136]: print a.decode('iso-8859-1')
ö
Das kleine Beispiel könntest Du zum Beispiel korrigieren, in dem Du den Inhalt von `text` von UTF-8 nach ISO-8859-1 umkodierst, oder in dem Du neben dem Content-Type-Header noch einen entsprechenden mit sendest, der dem Browser sagt, dass die Daten die danach kommen in UTF-8 kodiert sind.

Der `SyntaxError` zu dem ``.replace("ö","ö")`` führen kann, unter der Voraussetzung, dass sonst kein Syntaxfehler im Quelltext vorhanden ist, hat einen Text der erklärt warum der Fehler ausgelöst wird und eine URL wo man das noch einmal genauer nachlesen kann und wo auch steht was man dagegen tun kann.

Wobei der `UnicodeEncodeError` genau auftritt verrätst Du ja nicht, aber die Werte die `ElementTree` liefert sind etwas anderes als das was Du an `text` gebunden hast. Denn die `ElementTree` liefert keine Bytestrings sondern `unicode`-Objekte wenn etwas ausserhalb von ASCII enthalten ist. Bevor Du *das* also an irgend eine API weitergibst, die Bytestrings erwartet, musst *Du* dafür sorgen dass die so kodiert werden wie die API oder zum Beispiel der Browser das erwartet, der auf der anderen Seite auf die Daten wartet.

Wenn Du mit Zeichen arbeitest und dabei Unicode involviert ist, solltest Du intern mit Unicode arbeiten, und dabei so früh wie möglich Bytestrings dekodieren und so spät wie möglich das ganze in Bytestrings zurück wandeln, wenn eine API kein Unicode versteht.

Lesestoff im Wiki zum Thema: „Von Umlauten, Unicode und Encodings”.
Question
User
Beiträge: 2
Registriert: Freitag 24. August 2012, 19:32

@BlackJack: Vielen Dank für die Hilfe.

Hiermit

Code: Alles auswählen

text = result.content.decode('utf-8')
text= specialchars.handle(text)
text = text.encode('iso-8859-1','ignore')
hat es im Endeffekt geklappt die Zeichen auszutauschen. ("specialchars.handle" habe ich hier gefunden: http://www.python-forum.de/viewtopic.ph ... 3&p=131899)
Danach hat auch die Verarbeitung mit 'ElementTree' funktioniert.

Den "SyntaxError" bei "replace("ö","ö")" konnte ich durch

Code: Alles auswählen

# -*- coding: utf-8 -*-
am Anfang des Skripts beheben.
BlackJack

@Question: So kann man das natürlich auch „lösen”. Die Verarbeitung mit `ElementTree` hätte auch ohne funktioniert. Dein Problem war *nach* der Verarbeitung durch `ElementTree`.
Antworten