Hi!
In einem Script scrape ich Daten von Myspace und bekomme im Fall von "unbekannten" Zeichen (z.B. Umlauten) Unicode zurück - ansonsten "reine" Strings. Anstatt einem ü hab ich z.B. ü. Ich habe schon encode('utf-8').decode('latin-1') ausprobiert, aber das Ergebnis bleibt leider das selbe. Wie also kann ich die Zeichen richtig darstellen?
Das Skript: http://paste.pocoo.org/show/85526/
Ich hoffe, ihr könnt es auch nachvollziehen, ohne Myspace nutzen zu müssen.
Gruß
Sebastian
Wie Umlaute statt "komische Zeichen" anzeigen?
also das Ä1/4 kommt
hier her
hate ich auch schonmal
wenn du utf-8 verwendest musst du auch u"xxxx" verwenden sonst wird das nix
hier her
Code: Alles auswählen
# -*- coding: cp1252 -*-
wenn du utf-8 verwendest musst du auch u"xxxx" verwenden sonst wird das nix
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Das hier ist wirklich hilfreich (s. auch Thread weiter unten ):
[wiki]Von Umlauten, Unicode und Encodings?highlight=(umlaute)[/wiki]
Hat mich auch immer wieder beschäftigt Jahre lang - ich glaube so langsam hab ich das nun durchblickt, auch dank der Hilfe einiger Forummitglieder hier. Aber das wiki hat mir da wirklich sehr geholfen.
Sea-lives Beitrag vergisst Du lieber mal schnell
[wiki]Von Umlauten, Unicode und Encodings?highlight=(umlaute)[/wiki]
Hat mich auch immer wieder beschäftigt Jahre lang - ich glaube so langsam hab ich das nun durchblickt, auch dank der Hilfe einiger Forummitglieder hier. Aber das wiki hat mir da wirklich sehr geholfen.
Sea-lives Beitrag vergisst Du lieber mal schnell
Jupp. Ich hatte den Beitrag abgeschickt bevor ich mir die aktuelle Übersichtsseite angeguckt habe und daher den besagten Thread nicht gesehen.Hyperion hat geschrieben:Das hier ist wirklich hilfreich (s. auch Thread weiter unten ):
[wiki]Von Umlauten, Unicode und Encodings?highlight=(umlaute)[/wiki]
Habe jetzt an einer Zeile etwas rumgebastelt (ergibt sich aus dem Traceback) aber ich bekomme es immer noch nicht hin:
Code: Alles auswählen
>>> import mspdat
>>> msp = mspdat.Datagetter()
>>> msp.login('abc@xyz.de', 'pw123')
>>> print msp.get_moods(pretty=True)
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
print msp.get_moods(pretty=True)
File "C:\Python25\mspdat.py", line 57, in get_moods
return prettify_moods(data)
File "C:\Python25\mspdat.py", line 92, in prettify_moods
return '\n\n'.join(s).decode('iso-8859-1')
UnicodeEncodeError: 'ascii' codec can't encode characters in position 190-191: ordinal not in range(128)
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Dein Interpreter will standard mäßig ASCII ausgeben. Du bekommst aber eben Zeichen in Zeile 4 bei get_moods() zurück, die nicht in ASCII darstellbar sind. Du musst also mal gucken, dass Du beim print noch Kodierung angibst, die zur Ausgabe verwendet werden soll, also etwa so:
Code: Alles auswählen
print u"%s".encode("iso-8859-1") % msp.get_moods(pretty=True).decode("iso-8859-1")
@snafu: Nicht rumbasteln sondern verstehen was da passiert und gezielt handeln.
@Hyperion: Das ist ziemlich unsinnig. Du nimmst eine Unicode-Zeichenkette u'%s' und kodierst die als ISO-8859-1 ─ das ist '%s' etwas komplizierter geschrieben. Dann formatierst Du eine Unicode-Zeichenkette in eine normale Zeichenkette, was dazu führt, das die normale Zeichenkette erst einmal nach Unicode umgewandelt wird ─ aus dem '%s' wird also wieder u'%s'. *Das* kann man auch einfacher haben.
Die Frage ist, warum von `get_moods()` überhaupt eine Zeichenkette kommt und kein Unicode-Objekt. Wenn man aus den Seiten Unicode bekommt muss das ja schon mal völlig unnötigerweise umkodiert worden sein.
Wenn Textdaten das Programm betreten, sollte man sie sofort in Unicode umwandeln. `BeautifulSoup` und XML-Bibliotheken machen das schon. Innerhalb des Programms arbeitet man immer mit Unicode und erst zum spätmöglichsten Zeitpunkt, kurz bevor die Daten das Programm als Bytes verlassen müssen, wandelt man wieder entsprechend um. Alles andere ist unnötig kompliziert.
@Hyperion: Das ist ziemlich unsinnig. Du nimmst eine Unicode-Zeichenkette u'%s' und kodierst die als ISO-8859-1 ─ das ist '%s' etwas komplizierter geschrieben. Dann formatierst Du eine Unicode-Zeichenkette in eine normale Zeichenkette, was dazu führt, das die normale Zeichenkette erst einmal nach Unicode umgewandelt wird ─ aus dem '%s' wird also wieder u'%s'. *Das* kann man auch einfacher haben.
Die Frage ist, warum von `get_moods()` überhaupt eine Zeichenkette kommt und kein Unicode-Objekt. Wenn man aus den Seiten Unicode bekommt muss das ja schon mal völlig unnötigerweise umkodiert worden sein.
Wenn Textdaten das Programm betreten, sollte man sie sofort in Unicode umwandeln. `BeautifulSoup` und XML-Bibliotheken machen das schon. Innerhalb des Programms arbeitet man immer mit Unicode und erst zum spätmöglichsten Zeitpunkt, kurz bevor die Daten das Programm als Bytes verlassen müssen, wandelt man wieder entsprechend um. Alles andere ist unnötig kompliziert.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Das Print braucht doch kein String-Formatting.
Letztendlich ist es so: Man bekommt einen Bytestring rein, dekodiert den in Unicode und zur Ausgabe nutzt man wieder ein Encoding, das die Konsole versteht.
Wenn das so kompliziert ist, kannst du morgen zum Usertreffen in München kommen, genau das ist das Vortragsthema.
Letztendlich ist es so: Man bekommt einen Bytestring rein, dekodiert den in Unicode und zur Ausgabe nutzt man wieder ein Encoding, das die Konsole versteht.
Wenn das so kompliziert ist, kannst du morgen zum Usertreffen in München kommen, genau das ist das Vortragsthema.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Leider das selbe Problem:
Versuche ich die Position 191-192 anzuzeigen, kommt:
Vielleicht hilft das ja irgendwie...
Code: Alles auswählen
>>> print u"%s".encode("iso-8859-1") % msp.get_moods(pretty=True).decode("iso-8859-1")
Traceback (most recent call last):
File "<pyshell#3>", line 1, in <module>
print u"%s".encode("iso-8859-1") % msp.get_moods(pretty=True).decode("iso-8859-1")
UnicodeEncodeError: 'ascii' codec can't encode characters in position 191-192: ordinal not in range(128)
Code: Alles auswählen
>>> moods = msp.get_moods()
>>> from mspdat import prettify_moods as pretty
>>> print pretty(moods)[191:192]
Ã
Helfen würde die `repr()`-Form, damit man sieht was da *wirklich* heraus kommt und nicht wie Deine Konsole die Bytes interpretiert. Aber wie gesagt, `get_moods()` sollte Unicode oder Zeichenketten die nur ASCII enthalten zurück geben.
Und auch bei ``print`` musst Du Unicode-Objekte vorher entsprechend kodieren, damit es da keine Probleme gibt. Dass das in der Konsole meistens auf magische Weise klappt, ist keine Garantie.
Und auch bei ``print`` musst Du Unicode-Objekte vorher entsprechend kodieren, damit es da keine Probleme gibt. Dass das in der Konsole meistens auf magische Weise klappt, ist keine Garantie.
Tja, das frage ich mich auch.BlackJack hat geschrieben:Die Frage ist, warum von `get_moods()` überhaupt eine Zeichenkette kommt und kein Unicode-Objekt. Wenn man aus den Seiten Unicode bekommt muss das ja schon mal völlig unnötigerweise umkodiert worden sein.
Ist es denn möglich, mit BS zu parsen und dann mit der Syntax von lxml durch den Baum zu navigieren? Ich mag nämlich die Syntax von BS nicht so und befürchte, dass ich nicht mal so auf die Schnelle etwas äquivalentes zum jetzigen Code hinbekommen mit BS-Syntax hinbekommen würde.BlackJack hat geschrieben:Wenn Textdaten das Programm betreten, sollte man sie sofort in Unicode umwandeln. `BeautifulSoup` und XML-Bibliotheken machen das schon.
//edit: Okay, ich könnte natürlich den von BS geparsten Code als String ausgeben lassen und dann nochmal mit lxml drübergehen. Aber es geht doch sicher auch effizienter, oder?
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Und wozu das ganze? html5lib und lxml.html existieren.snafu hat geschrieben:Ist es denn möglich, mit BS zu parsen und dann mit der Syntax von lxml durch den Baum zu navigieren? Ich mag nämlich die Syntax von BS nicht so und befürchte, dass ich nicht mal so auf die Schnelle etwas äquivalentes zum jetzigen Code hinbekommen mit BS-Syntax hinbekommen würde.
//edit: Okay, ich könnte natürlich den von BS geparsten Code als String ausgeben lassen und dann nochmal mit lxml drübergehen. Aber es geht doch sicher auch effizienter, oder?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
Hm ... ok ... ich versuche das mal grad nachzuvollziehen.BlackJack hat geschrieben: @Hyperion: Das ist ziemlich unsinnig. Du nimmst eine Unicode-Zeichenkette u'%s' und kodierst die als ISO-8859-1 ─ das ist '%s' etwas komplizierter geschrieben. Dann formatierst Du eine Unicode-Zeichenkette in eine normale Zeichenkette, was dazu führt, das die normale Zeichenkette erst einmal nach Unicode umgewandelt wird ─ aus dem '%s' wird also wieder u'%s'. *Das* kann man auch einfacher haben.
get_moods() liefert also def. einen Bytestring zurück, vermutlich iso-8859-1 encodiert. Die Konsole meckert wegen Zeichen, die die ASCII-Kodierung nicht darstellen kann. Also muss man doch print mitteilen, dass man kein ASCII sondern, iso-8859-1 Text ausgeben will. Ich dachte immer über einwiki hat geschrieben: Wenn man einen Text mit Umlauten an die Konsole (in unserem Fall STDOUT) schicken möchte, dann muss man diesen Text in das Encoding der Konsole umwandeln.
Code: Alles auswählen
u"irgend ein Text".encode("iso-8859-1")
%s ist einfach nur Teil des String-Formattings, was du dir - wie schon gesagt wurde - aber auch sparen kannst.Hyperion hat geschrieben:Wenn ich BlackJack richtig verstanden habe, so bewirkt der "%"-Operator ein implizites umkodieren in das Byteformat des Bytestrings?
repr(pretty(moods)) liefert übrigens das zurück (Auszug) :
Code: Alles auswählen
<Assen> ........................................................ <Am 06.Aug.2008.>\\ntraurig\\n\\n<schmockefuckanalpropaganda(K\\xc3\\xb6nig)> ab in stadtgarten alle man(auf den hund gekommen) <Am 04.Aug.2008.>\\nquietschfidel\\n\\n<Ace L. Chuck> Dirty old Town... <Am 27.Jul.2008.>\\nerleichtert\\n\\n<The kid you never wanted around.> wohnt jezz auch wieder in schalke-ost! <Am 25.Jul.2008.>\\nersch\\xc3\\xb6pft\\n\\n<Dino> : wuff! <Am 15.Jul.2008.>\\nam Chillen\\n\\n<Philo> isst gerade. <Am 13.Jul.2008.>\\nam Rocken\\n\\n<Dirrrty Sanchez from Outta Space> quo <Am 22.Jun.2008.>\\ntriumphierend\\n\\n<Horst> endlich neue wohnung UND internet!!! <Am 10.Jun.2008.>\\naufgedreht\\n\\n<Elektro_Deluxe> : In Deinem erweiterten Netzwerk <Am 08.Mai.2008.>\\nritterlich\\n\\n
Du meinst, ich soll mit lxml parsen (mit html5lib tu ich's ja schon und baue daraus einen lxml-Baum)? Das Problem ist, dass lxml wohl nicht so fehlertolerant ist. Zumindest bekomme bei dessen Parser nichts brauchbares zurück.Leonidas hat geschrieben:Und wozu das ganze? html5lib und lxml.html existieren.
-
- Python-Forum Veteran
- Beiträge: 16025
- Registriert: Freitag 20. Juni 2003, 16:30
- Kontaktdaten:
Und wie sieht das mit html5lib aus?snafu hat geschrieben:Du meinst, ich soll mit lxml parsen (mit html5lib tu ich's ja schon und baue daraus einen lxml-Baum)? Das Problem ist, dass lxml wohl nicht so fehlertolerant ist. Zumindest bekomme bei dessen Parser nichts brauchbares zurück.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Ist myspace wirklich so kaputt oder hast du nur einfach nicht mit lxml.html geparst (sondern mit lxml.etree)?snafu hat geschrieben:Du meinst, ich soll mit lxml parsen (mit html5lib tu ich's ja schon und baue daraus einen lxml-Baum)? Das Problem ist, dass lxml wohl nicht so fehlertolerant ist. Zumindest bekomme bei dessen Parser nichts brauchbares zurück.Leonidas hat geschrieben:Und wozu das ganze? html5lib und lxml.html existieren.
@Hyperion: Du hast da im Endeffekt eine Unicode-Zeichenkette stehen, die Du eben *nicht* explizit kodierst, sondern das Python überlässt. Und wenn da was ausserhalb von ASCII enthalten ist, dann kann's krachen.
Nochmal langsam ``u'%s'.encode('iso-8859-1') % get_moods().decode("iso-8859-1")`` Schritt für Schritt. Der Ausdruck vor dem ``%`` wird zu '%s', das hatten wir ja schon. Gehen wir mal davon aus `get_moods()` gibt 'mööp' als 'iso-8859-1' kodiert zurück, dann wird daraus u'm\xf6\xf6p'. Im nächsten Schritt wird also ``'%s' % u'm\xf6\xf6p'`` ausgwertet. Bei solchen Operationen mit Zeichenketten und Unicode-Objekten wird immer die Zeichenkette implizit zu Unicode umgewandelt (mit ASCII als angenommene Kodierung, aber das ist hier ja kein Problem). Das ist so ähnlich wie Operationen mit ganzen Zahlen und Fliesskommazahlen, wo immer mit Fliesskommazahlen weiter gearbeitet wird. Also läuft's auf ``u'%s' % u'm\xf6\xf6p'`` raus, was auch wieder so eine unnütze Aktion ist, weil's natürlich wieder u'm\xf6\xf6p' als Ergebnis hat. Und da steht jetzt ein ``print`` davor. Damit liefert man sich wieder dem Problem aus, dass das klappen kann, oder auch nicht, je nachdem ob Python die Kodierung von `sys.stdout` richtig raten konnte oder nicht.
Nochmal langsam ``u'%s'.encode('iso-8859-1') % get_moods().decode("iso-8859-1")`` Schritt für Schritt. Der Ausdruck vor dem ``%`` wird zu '%s', das hatten wir ja schon. Gehen wir mal davon aus `get_moods()` gibt 'mööp' als 'iso-8859-1' kodiert zurück, dann wird daraus u'm\xf6\xf6p'. Im nächsten Schritt wird also ``'%s' % u'm\xf6\xf6p'`` ausgwertet. Bei solchen Operationen mit Zeichenketten und Unicode-Objekten wird immer die Zeichenkette implizit zu Unicode umgewandelt (mit ASCII als angenommene Kodierung, aber das ist hier ja kein Problem). Das ist so ähnlich wie Operationen mit ganzen Zahlen und Fliesskommazahlen, wo immer mit Fliesskommazahlen weiter gearbeitet wird. Also läuft's auf ``u'%s' % u'm\xf6\xf6p'`` raus, was auch wieder so eine unnütze Aktion ist, weil's natürlich wieder u'm\xf6\xf6p' als Ergebnis hat. Und da steht jetzt ein ``print`` davor. Damit liefert man sich wieder dem Problem aus, dass das klappen kann, oder auch nicht, je nachdem ob Python die Kodierung von `sys.stdout` richtig raten konnte oder nicht.
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
@BlackJack: Danke für die ausführliche Erklärung Dass bei Operationen mit Zeichenketten und Unicode die Zeichenkette immer intern in Unicode gewandelt wird, war mir wirklich nicht bewusst.
Wie geht man denn nun aber in diesem Falle vor? Also kann ich print irgend wie klar machen, welche Kodierung ein String hat oder wie es etwas korrekt ausgeben soll? In obigen Fall will es ja offensichtlich den ByteString als ASCII ausgeben, was ja das Problem darstellt.
Wie geht man denn nun aber in diesem Falle vor? Also kann ich print irgend wie klar machen, welche Kodierung ein String hat oder wie es etwas korrekt ausgeben soll? In obigen Fall will es ja offensichtlich den ByteString als ASCII ausgeben, was ja das Problem darstellt.
Naja, entweder man kodiert das Unicode-Objekt direkt beim ``print`` in Bytes, oder man "wrappt" die Ausgabe `sys.stdout` mit einem entsprechenden Objekt aus dem `encodings`-Modul und benutzt dort dann die `write()`-Methode.
Welche Kodierung das Programm, das an `sys.stdout` auf Bytes lauscht, erwartet, kann man nur raten und man sollte IMHO immer die Möglichkeit bieten den Anwender des Programms entscheiden zu lassen.
Welche Kodierung das Programm, das an `sys.stdout` auf Bytes lauscht, erwartet, kann man nur raten und man sollte IMHO immer die Möglichkeit bieten den Anwender des Programms entscheiden zu lassen.