urllib -> KML (utf-8) zu unicode

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

hi...

ich möchte mittels urllib (ggf. auch urllib2, falls das nötig ist) eine kml-datei runterladen. kml-dateien sind, ähnlich wie xml, in utf-8 kodiert.

im prinzip wird folgendes gemacht:

Code: Alles auswählen

import urllib

url = 'http://maps.google.de/maps?f=d&hl=de&geocode=&saddr=50.096711%208.684174&daddr=50.096711%208.684174&output=kml'

data = urllib.open(url)
kml = data.read()
da kml definitiv in utf-8 kodiert ist dürfte eigentlich

Code: Alles auswählen

>>> uni = unicode(kml,'utf-8')

Traceback (most recent call last):
  File "<pyshell#51>", line 1, in <module>
    uni = unicode(kml,'utf-8')
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 105-108: invalid data
funktionieren. tut's aber nicht. meine theore ist ein fehlender BOM in der kml-variable.
probehalber hab ich data einfach mal gespeichert, und wie ich feststellen durfte wurde die datei auch nicht als utf-8 gespeichert. lade ich hingegen die datei per browser runter und ändere die dateiendung in txt, dann erkennt der editor die datei als utf-8.
beim rozess des herunterladens geht also meiner theorie nach der BOM verloren, weshalb ich den string dann nicht in unicode konvertieren kann.
selbiges gilt übrigens auch, wenn ich die kml-datei per urlretrieve runterlade.

nundenn, kann mir jemand erklären, wie ich in dieser situation zu einem unicode-string komme?

vielen dank im vorraus... :)
BlackJack

Das hat nichts mit BOM oder nicht zu tun, sondern die Daten sind einfach kaputt. Sprich, die XML-Zeile am Anfang behauptet es sei UTF-8, aber das stimmt nicht.
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

@BlackJack

wenn ich dieselbe datei mit nem normalen web-browser runterlade ist sie aber defacto in utf-8 kodiert...
kml-dateien funktionieren schließlich weltweit. und ich behaupte, dass die google-mitarbeiter durchaus in er lage sind korrekte utf-8-dateien zu erstellen...

spielt aber auch keine rolle, denn ich will ja nur wissen, wie ich aus der kml-variable nen unicode-string kriege. wenn ich zum dekodieren cp1252 nehme geht's. das wird jedoch im iran nicht mehr gehen. ergo ist das keine "professionelle" lösung die global nutzbar ist.
lunar

szallah hat geschrieben:wenn ich dieselbe datei mit nem normalen web-browser runterlade ist sie aber defacto in utf-8 kodiert...
Und was kommt dabei raus, wenn du die Rückgabe von "data.read()" in eine Datei schreibst? Ist die dann auch utf-8 kodiert?
kml-dateien funktionieren schließlich weltweit. und ich behaupte, dass die google-mitarbeiter durchaus in er lage sind korrekte utf-8-dateien zu erstellen...
Das mag ja sein, Fakt ist aber, dass die Daten, die du da erhältst, nun mal nicht korrekt UTF-8 enkodiert sind. Über die Ursache kann man nur mutmaßen, über das Symptom besteht allerdings kein Zweifel.
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

lunar hat geschrieben:
szallah hat geschrieben:wenn ich dieselbe datei mit nem normalen web-browser runterlade ist sie aber defacto in utf-8 kodiert...
Und was kommt dabei raus, wenn du die Rückgabe von "data.read()" in eine Datei schreibst? Ist die dann auch utf-8 kodiert?
wenn ich die datei mit dem browser runterlade (was ganz einfach geht indem man die url von oben in die adressleiste einfügt), dann ist sie in utf-8 kodiert. öffne ich die browser-datei in python, dann lässt sich alles wunderbar nach unicode konvertieren.
wenn ich sie mit urlretrieve oder .write() abspeichere NICHT, was ja der grund ist weshalb ich hier überhaupt den post eröffnet habe.
kml-dateien funktionieren schließlich weltweit. und ich behaupte, dass die google-mitarbeiter durchaus in er lage sind korrekte utf-8-dateien zu erstellen...
Das mag ja sein, Fakt ist aber, dass die Daten, die du da erhältst, nun mal nicht korrekt UTF-8 enkodiert sind. Über die Ursache kann man nur mutmaßen, über das Symptom besteht allerdings kein Zweifel.
inwiefern nicht korrekt als utf-8 kodiert? die umlaute sind in der datei genau so drin, wie man es von einem utf-8-kodierten string erwartet, bzw., wie ich es erwarte... also z.b.

Code: Alles auswählen

v = 'ß'
v
'\xdf'
das ist meines wissens nach utf-8... bzw., aufgrund des aufbau's ist es in dem fall auch cp1252 und latin-1, aber in utf-8 wird das ß meines wissens nach ganz genauso kodiert.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

szallah hat geschrieben:
lunar hat geschrieben:
szallah hat geschrieben:wenn ich dieselbe datei mit nem normalen web-browser runterlade ist sie aber defacto in utf-8 kodiert...
Und was kommt dabei raus, wenn du die Rückgabe von "data.read()" in eine Datei schreibst? Ist die dann auch utf-8 kodiert?
wenn ich die datei mit dem browser runterlade (was ganz einfach geht indem man die url von oben in die adressleiste einfügt), dann ist sie in utf-8 kodiert. öffne ich die browser-datei in python, dann lässt sich alles wunderbar nach unicode konvertieren.
wenn ich sie mit urlretrieve oder .write() abspeichere NICHT, was ja der grund ist weshalb ich hier überhaupt den post eröffnet habe.
Und was hindert den Browser daran, eine Datei die als CP1215 reinkommt (Chardet kann ja sniffen) als UTF-8 abzuspeichern? Heißt: du bekommst mit Python die Originaldaten, vom Browser bekommst du bereits verarbeitetes Zeug.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

@Leonidas

und wie veranlasse ich Python dazu in diesem konkreten fall die Daten die reinkommen, so wie der browser es macht, in UTF-8 zu kodieren? unicode(xyz,'utf-8') führt, wie im eingangspost beschrieben ja zu nem decode-error.

oder vereinfacht gefragt:
ist das wonach ich hier frage technisch realisierbar, oder stößt python hierbei an seine grenzen?
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

szallah hat geschrieben:und wie veranlasse ich Python dazu in diesem konkreten fall die Daten die reinkommen, so wie der browser es macht, in UTF-8 zu kodieren? unicode(xyz,'utf-8') führt, wie im eingangspost beschrieben ja zu nem decode-error.
Letztendlich willst du das eigentlich so:

Eingabedaten (irgendein Encoding) -> Dein Programm (intern mit Unicode arbeiten) -> Ausgabedaten (UTF-8)

Nun, dein Problem ist, dass du das Encoding nicht weißt, oder? Oder ist es tatsächlich CP1215? Wenn ja, dann machst du ``eingabestring.decode('cp1215')`` und heraus kommt Unicode - wunderbar.

Ein Browser hingegen rät oftmals was für ein Encoding vorliegt, aber ich würde dir wirklich davon abraten, das Encoding erraten zu wollen denn das funktioniert nicht immer zuverlässig.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BlackJack

@szallah: Python stösst hier nicht an Grenzen, sondern das XML ist einfach kaputt. Technisch realisierbar ist das nur bis zu einem gewissen Grad, denn man *kann* nur raten welche Kodierung tatsächlich verwendet wurde, sich aber nicht *sicher* sein.

Vielleicht solltest Du Dich auch mal an die Quelle wenden und fragen warum die's nicht gebacken bekommen korrektes XML zu erzeugen.
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

@Leonidas & BlackJack

ok, dann liefert google-maps kein gescheites XML... ich bin anfänger, und kann das deshalb nicht beurteilen. ich vertraue euch da einfach mal.

jetzt stellt sich mir die frage, wie ich python dazu bringe, die daten genauso wie der IE als UTF-8 zu behandeln. ob es nun wirklich utf-8 ist oder nicht spielt jetzt keine rolle. ich will einfach nur wissen, ob sich das verhalten vom IE in python reproduzieren lässt, und wenn ja, wie - ganz egal ob da nun utf-8 verschickt wird oder nicht.
die vom IE gespeicherte kml-datei kann ich nunmal in jedem fall mit 'utf-8' als parameter in unicode konvertieren, sei der inhalt nun mit kyrillischer oder sonstwas für einer schrift kodiert. und das will ich in python auch.
so nach dem motto:

Code: Alles auswählen

data = urllib.urlopen(url,'force utf-8')
ob das nun unelegant und unprosfessionell oder sonst was ist spielt für mich persönlich keine rolle. ich will die daten einfach nur so haben, wie der IE sie liefert, und das ist UTF-8...
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

szallah hat geschrieben:jetzt stellt sich mir die frage, wie ich python dazu bringe, die daten genauso wie der IE als UTF-8 zu behandeln. ob es nun wirklich utf-8 ist oder nicht spielt jetzt keine rolle. ich will einfach nur wissen, ob sich das verhalten vom IE in python reproduzieren lässt, und wenn ja, wie - ganz egal ob da nun utf-8 verschickt wird oder nicht.
die vom IE gespeicherte kml-datei kann ich nunmal in jedem fall mit 'utf-8' als parameter in unicode konvertieren, sei der inhalt nun mit kyrillischer oder sonstwas für einer schrift kodiert. und das will ich in python auch.
Du willst nicht alles als UTF-8 behandeln, denn das hast du ja schon versucht und es funktioniert nicht, sondern du willst das Encoding raten, in dem Fall sieh' dir mal Chardet an.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

@leonidas

das ist es aber nicht was ich will... ich will ZWINGED utf-8... ohne wenn und aber, NUR utf-8, ganz egal wie naiv das sein mag, das ist es was ich will...

machen wir's anders:
lad dir unter diesem link die kml-datei runter.
öffne diese mal auf der python-shell und guck dir den inhalt an... das iss ganz fein sauberes utf-8, und per print bekommt man sogar schön das kyrillisch angezeigt...

diesen vorgang will ich in python haben... nichts mit encoding raten oder sonstwas, sondern GENAU diesen... wenn das voraussetzt, dass ich dem programm einfach wget beifüge und das dann damit runterlade, ok, mach ich's halt so... eine python-interne lösung wäre mir halt lieber...
BlackJack

@szallah: Du solltest Dich echt mal mit Kodierungen auseinander setzen. Deine komische "ich will aber"-Trotzhaltung wird Dir nichts bringen, weil man halt raten *muss* wenn die Kodierung gar nicht oder falsch angegeben wurde. Das geht gar nicht anders. wget hilft da auch nicht weiter.

Wenn ich den angegebenen Link runterlade sehe ich übrigens kyrillischen Zeichen sondern einen Haufen Zeichenreferenzen. Das wird erst durch einen XML-Parser zu Zeichen.
lunar

szallah hat geschrieben:das ist es aber nicht was ich will... ich will ZWINGED utf-8... ohne wenn und aber, NUR utf-8, ganz egal wie naiv das sein mag, das ist es was ich will...
Dann wende dich an Google. Davon, dass du hier rumschreist, wird deren XML auch nicht besser :roll:
machen wir's anders:
lad dir unter diesem link die kml-datei runter.

Code: Alles auswählen

>>> import urllib2
>>> link = 'http://maps.google.de/maps?f=d&hl=de&geocode=&saddr=50.096711%208.684174&daddr=50.096711%208.684174&output=kml'
>>> urllib2.urlopen(link).read().decode('utf-8')
------------------------------------------------------------
Traceback (most recent call last):
  File "<ipython console>", line 1, in <module>
  File "/usr/lib/python2.5/encodings/utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec cant decode bytes in position 105-108: invalid data

>>> link = 'http://maps.google.de/maps?f=d&hl=de&geocode=&saddr=55.736226%2037.66465&daddr=55.736226%2037.66465&output=kml'
>>> urllib2.urlopen(link).read().decode('utf-8')
u'<?xml version="1.0" encoding="UTF-8"?><kml xmlns="http://earth.google.com/kml/2.0">[...]
Wie du siehst, erzeugt dieser Link im Gegensatz zu dem des ersten Postings korrektes XML mit korrektem Encoding.
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Irgendwie hat Google sein KML nicht im Griff.

Die erste Datei ist definitiv kein gültiges XML, da sie zwar behauptet, UTF-8-kodiert zu sein, aber eher ISO-8859-X-kodiert ist. Der Ausdruck "<?xml version="1.0" encoding="UTF-8"?> ist somit eine glatte Lüge und macht die Datei invalid. Das, was bei der zweiten URL kommt, kann man als UTF-8 bezeichnen, nutzt aber gar nicht die Kodierung, sondern nur das ASCII-Subset und benutzt stattdessen numerische Entities. Somit auch kein echtes UTF-8.

Da hätte ich mehr von Google erwartet. Hier ist der Bug.

Stefan
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

@BlackJack

also wenn ich die datei im IE runterlade und in python öffne sieht das so aus: (und nein, da ist nix gefaked oder sonst was, das ist bei mir wirklich so)
Bild

ich sehe da einerseits kyrlilische zeichen (per print), und nen utf-8 kodierten string...

ist der IE also schlau genug das "kaputte" xml selbstständig nach utf-8 umzuwandeln? wenn ja, dann muss ich mich wohl schlau machen wie ich python dazu bringe das kaputte xml zu reparieren...
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

sma hat geschrieben:Da hätte ich mehr von Google erwartet. Hier ist der Bug.
Also laut dem Bug kann man eher nach dem Header "Content-Type" im HTTP gehen. Kannst ja diesen auslesen und verwenden damit du Unicode erstellen kannst und nacher in UTF-8 wandeln.

Gruss
szallah
User
Beiträge: 14
Registriert: Dienstag 27. Mai 2008, 07:31

@Rayo

das war die information die ich gebraucht habe...

folgendes funktioniert:

Code: Alles auswählen

url = 'http://maps.google.de/maps?f=d&hl=de&geocode=&saddr=55.736226%2037.66465&daddr=55.736226%2037.66465&output=kml'
user_agent = 'Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 6.0)'
data = ''
headers = { 'User-Agent' : user_agent }
req = urllib2.Request(url, data, headers)
resp = urllib2.urlopen(req)
response = resp.read()
uni = unicode(response,'utf-8')
vielen dank... :)
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Da funktioniert auch ohne den Header :) Die Datei hat nur ascii-Zeichen drin. Ich meinte den Antwort-Header vom Server und nicht den Request-Header.

Gruss
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

sma hat geschrieben:Da hätte ich mehr von Google erwartet. Hier ist der Bug.
Das ist echt eine peinliche Sache und das auf den Bug immer nur eine Reaktion pro Monat kommt ist irgendwie schwach.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Antworten