Fehlerhapfte String Formatierung (Einst%C3%BCrzende)

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
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Hallo zusammen!

Ich schreibe gerade einen kleinen Cover Downloader für Amazon Cover. Dabei wird eine Verzeichnisstruktur rekursiv ausgelesen und im Falle eines nicht vorhandenen Covers für ein Verzeichnis dieses von Amazon geholt. Da die Verzeichnisse nach dem Schema "Künstler/Album" benannt sind, splitte ich das Verzeichnis einfach auf und suche über die Amazon REST API danach.

Mein Problem ist nun: Ich schaffe es nicht, Verzeichnisse mit Sonderzeichen (Umlaute...) korrekt an Amazon zu übertragen.

Wenn ich es mit urllib.urlencode() mache, wird es wie folgt verschlüsselt:
Einstürzende => Einst%C3%BCrzende. Bei Amazon landet Einstürzende und führt natürlich zu keinem Ergebnis.
Das gleiche passiert, wenn ich urlencode() völlig weg lasse: Dann steht in der URL Klartext "Einstürzende", bei Amazon landet aber wieder Einstürzende.

Hat jemand von euch eine Idee, wie ich den String so formatieren könnte, dass er bei Amazon richtig ankommt?

lG

brb
Benutzeravatar
HWK
User
Beiträge: 1295
Registriert: Mittwoch 7. Juni 2006, 20:44

Das Encoding bei Amazon ist wohl nicht UTF-8 wie bei Dir. Du müßtest den String erst im Encoding von Amazon encodieren und dann urlencoded versenden.

Code: Alles auswählen

>>> urlencode({'test':'Einstürzende'.decode('cp1252').encode('utf-8')})
'test=Einst%C3%BCrzende'
Du musst also nur noch das benötigte Encoding herausfinden. :wink:
MfG
HWK
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Es scheint, als ob urllib.urlencode() anders enkodiert als Amazon es erwartet. Ich habe einfach folgende "hau mich ich kann nix" Variante ersonnen, die für die von mir getesteten Fälle funktioniert (umlaute, leerzeichen etc).

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: utf-8 -*-

codes = {
    " " : "%20",
    "!" : "%21",
    "\"" : "%22",
    "#" : "%23",
    "$" : "%24",
    "%" : "%25",
    "&" : "%26",
    "'" : "%27",
    "(" : "%28",
    ")" : "%29",
    "*" : "%2A",
    "+" : "%2B",
    "," : "%2C",
    "-" : "%2D",
    "." : "%2E",
    "/" : "%2F",
    ":" : "%3A",
    ";" : "%3B",
    "<" : "%3C",
    "=" : "%3D",
    ">" : "%3E",
    "?" : "%3F",
    "@" : "%40",
    "[" : "%5B",
    "\\" : "%5C",
    "]" : "%5D",
    "^" : "%5E",
    "_" : "%5F",
    "`" : "%60",
    "{" : "%7B",
    "|" : "%7C",
    "}" : "%7D",
    "~" : "%7E",
    " " : "%7F",
    "€" : "%80",
    " " : "%81",
    "‚" : "%82",
    "ƒ" : "%83",
    "„" : "%84",
    "…" : "%85",
    "†" : "%86",
    "‡" : "%87",
    "ˆ" : "%88",
    "‰" : "%89",
    "Š" : "%8A",
    "‹" : "%8B",
    "Œ" : "%8C",
    " " : "%8D",
    "Ž" : "%8E",
    " " : "%8F",
    " " : "%90",
    "‘" : "%91",
    "’" : "%92",
    "“" : "%93",
    "”" : "%94",
    "•" : "%95",
    "–" : "%96",
    "—" : "%97",
    "˜" : "%98",
    "™" : "%99",
    "š" : "%9A",
    "›" : "%9B",
    "œ" : "%9C",
    " " : "%9D",
    "ž" : "%9E",
    "Ÿ" : "%9F",
    " " : "%A0",
    "¡" : "%A1",
    "¢" : "%A2",
    "£" : "%A3",
    " " : "%A4",
    "¥" : "%A5",
    "|" : "%A6",
    "§" : "%A7",
    "¨" : "%A8",
    "©" : "%A9",
    "ª" : "%AA",
    "«" : "%AB",
    "¬" : "%AC",
    "¯" : "%AD",
    "®" : "%AE",
    "¯" : "%AF",
    "°" : "%B0",
    "±" : "%B1",
    "²" : "%B2",
    "³" : "%B3",
    "´" : "%B4",
    "µ" : "%B5",
    "¶" : "%B6",
    "·" : "%B7",
    "¸" : "%B8",
    "¹" : "%B9",
    "º" : "%BA",
    "»" : "%BB",
    "¼" : "%BC",
    "½" : "%BD",
    "¾" : "%BE",
    "¿" : "%BF",
    "À" : "%C0",
    "Á" : "%C1",
    "Â" : "%C2",
    "Ã" : "%C3",
    "Ä" : "%C4",
    "Å" : "%C5",
    "Æ" : "%C6",
    "Ç" : "%C7",
    "È" : "%C8",
    "É" : "%C9",
    "Ê" : "%CA",
    "Ë" : "%CB",
    "Ì" : "%CC",
    "Í" : "%CD",
    "Î" : "%CE",
    "Ï" : "%CF",
    "Ð" : "%D0",
    "Ñ" : "%D1",
    "Ò" : "%D2",
    "Ó" : "%D3",
    "Ô" : "%D4",
    "Õ" : "%D5",
    "Ö" : "%D6",
    " " : "%20", #%D7
    "Ø" : "%D8",
    "Ù" : "%D9",
    "Ú" : "%DA",
    "Û" : "%DB",
    "Ü" : "%DC",
    "Ý" : "%DD",
    "Þ" : "%DE",
    "ß" : "%DF",
    "à" : "%E0",
    "á" : "%E1",
    "â" : "%E2",
    "ã" : "%E3",
    "ä" : "%E4",
    "å" : "%E5",
    "æ" : "%E6",
    "ç" : "%E7",
    "è" : "%E8",
    "é" : "%E9",
    "ê" : "%EA",
    "ë" : "%EB",
    "ì" : "%EC",
    "í" : "%ED",
    "î" : "%EE",
    "ï" : "%EF",
    "ð" : "%F0",
    "ñ" : "%F1",
    "ò" : "%F2",
    "ó" : "%F3",
    "ô" : "%F4",
    "õ" : "%F5",
    "ö" : "%F6",
    "÷" : "%F7",
    "ø" : "%F8",
    "ù" : "%F9",
    "ú" : "%FA",
    "û" : "%FB",
    "ü" : "%FC",
    "ý" : "%FD",
    "þ" : "%FE",
    "ÿ" : "%FF"
}

def urlencode(text):
    text = text.replace("%", codes["%"])
    for code in codes:
        if code in text and code != "%":
            print code
            text = text.replace(code, codes[code])
    return text
Folgende Anmerkungen: Viele normale Buchstaben und Zahlen habe ich entfernt, prinzipiell hat natürlich jeder Buchstabe seine Entsprechung. Zuerst werden natürlich alle "%" ersetzt, da diese später ein kodiertes Zeichen einleiten und dann nicht mehr ersetzt werden sollen.
In dieser Variante wird jetzt jedes Zeichen im Dict darauf getestet, ob es im String vorkommt und dann ggf. ersetzt.

Wie ich gerade feststelle, werden die Zeichen nach dem Schema "'%%%i' % ord(char)" formatiert. Oben genannter Code kann also deutlich gestrafft werden.

lG

brb
BlackJack

@Barabbas: Bravo Du hast `urlencode()` umständlich nachgebaut. Das Problem ist die Kodierung des (Byte)Strings bevor Du `urlencode()` aufrufst.
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

wenn ich den selben string einmal an urlencode() und einmal an mein_urlencode() übergebe, erhalte ich unterschiedliche Ergebnisse.
Das Eine ist unbrauchbar, das Andere nicht. Da ich bisher keine Kodierung finden konnte, die funktioniert, betrachte ich obigen Code vorerst als Lösung, bis es eine Bessere gibt.
BlackJack

Okay, dann ist der Quelltext also UTF-8 kodiert und die Schlüssel sind nicht alle 1 Byte lang. Da habe ich mich von der Aussage mit `ord()` irritieren lassen. *Das* wäre nämlich das was `urlencode()` macht.

Die Kodierung ist ISO-8859-15. Stand das nicht bei der Tabelle, wo Du die Codes abgetippt hast? Oder wie bist Du auf die Werte gekommen?
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

Die Werte habe ich tatsächlich aus einer Tabelle, die ich irgendwo in der Amazon-Dokumentation gefunden habe. Dort wurde auf diese Seite verlinkt.

So wie ich das verstehe sind die Werte einfach nur die Hex-Werte des entsprechenden Ansi-Zeichencodes. Ich habe auch keine Ahnung, warum urllib.urlencode() da zu anderen Ergebnissen kommt, habe - wie gesagt- schon die geläufigsten Kodierungen getestet.


---
Hm, mit iso-8859-15 geht es tatsächlich. Ich hatte das schon probiert, aber anscheinend dekodiert statt enkodiert. Blöder Fehler aber jetzt geht es; Amazon spezifiziert zwar das Zeichen "%20" für Leerzeichen aber mit "+" geht es anscheinend auch. Scheint zu gehen.

Danke dir!
Y0Gi
User
Beiträge: 1454
Registriert: Freitag 22. September 2006, 23:05
Wohnort: ja

`%20` ist das URL-Encoding eines Leerzeichens, aber es gibt auch das "Plus-Quoting", bei dem ein `+` als Maskierung dient. Das ist beides nichts Amazon-Spezifisches.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Nein, die selbstgemachte Kodierung dort ist nicht ISO-8859-15 (aka Latin-9) sondern das Windows-spezifische CP1252. Bei ISO-8859-15 würde das €-Zeichen auf A4 liegen (und das internationale Währungssymbol ¤ von ISO-8859-1 (Latin-1) ersetzen) sowie noch ein paar andere Unterschiede haben. Die zitierte Tabelle titelt mit "ASCII-Charakter" die Spalte falsch, denn der ASCII-Code endet bei 127. Im Text wird zudem fälschlich ISO-8859-1 erwähnt. Die Seite ist Müll.

Stefan
Barabbas
User
Beiträge: 349
Registriert: Dienstag 4. März 2008, 14:47

auch wenn es unprofessionell wirkt (was den Tatsachen entspräche, da ich das Ganze ja nur aus Jux und Dollerei betreibe): Ich habe diesem ganzen Sprach-String-Zeichenketten-Formatierungs-Kram schon immer sehr ahnungslos gegenüber gestanden. Irgendwie wirkt der Beitrag von sma ziemlich... absurd (natürlich nur auf mich, da ich ja davon auch herzlich wenig verstehe).
Punktum, danke für eure Hilfe es läuft und bei Zeiten werde ich Bericht erstatten, was Amazon nun tatswahrhaftig erwartet.

@Yogi: Das mit %20 und + kenne ich auch, schon klar, dass Amazon das nicht erfunden hat. Mit "amazon spezifiziert..." meinte ich nur, dass Amazon schreibt, dass die API das so erwartet. Streng genommen spezifizieren die also nicht das urlencoding sondern die String-Verarbeitung der API, da hast du natürlich recht.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Barabbas hat geschrieben:auch wenn es unprofessionell wirkt (was den Tatsachen entspräche, da ich das Ganze ja nur aus Jux und Dollerei betreibe): Ich habe diesem ganzen Sprach-String-Zeichenketten-Formatierungs-Kram schon immer sehr ahnungslos gegenüber gestanden. Irgendwie wirkt der Beitrag von sma ziemlich... absurd (natürlich nur auf mich, da ich ja davon auch herzlich wenig verstehe).
Wenn du dich nicht damit beschäftigst was sma da genau schreibt, was das bedeutet etc. dann wird es auch immer absurd bleiben. Unverständnis ist nicht unprofessionell. Mangel an besserungswillen ist schon eher unprofessionell. Und solltest dich besser mal mit den Unicode-Ressourcen im Wiki bekannt machen, es gibt mindestens zwei Artikel dazu und auch meine Folien die zum Verständiss hilfreich sein könnten. Außerdem die Forensuche. Wenn du keine passenden Antworten findest, dann darfst du natürlich auch neue Threads starten und dort Fragen stellen - Fragen bei denen der Autor schon vorher die vorhandenen Ressourcen ausgeschöpft hat und selbst rumprobiert hat sich natürlich gern gesehen und helfen vielleicht auch anderen die in Zukunft die selbe Frage haben könnten.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten