Seite 1 von 1

urlopen(url).read() in Python3

Verfasst: Samstag 26. September 2009, 18:43
von gfmwm
Hallo alle zusammen,

ich möchte gerne den Quelltext einer Internetseite in einen String einlesen. Das habe ich bis jetzt:

Code: Alles auswählen

from html.parser import HTMLParser
from urllib.request import urlopen

url = "http://www.google.de"
byt = urlopen(url).read()

res = byt.decode('utf-8')

print(res)
Da die funktion read() mit Python3 ein bytearray zurückgibt versuche ich dieses in UTF-8 zu kodieren. Das klappt aber nicht:
UnicodeDecodeError: 'utf8' codec can't decode bytes in position 3637-3642: unsupported Unicode code range
Hat jemand eine Idee?

Danke schonmal.
Gruß Dieter

Verfasst: Samstag 26. September 2009, 19:17
von EyDu
Hallo und willkommen im Forum.

Da hapert es gleich an ein paar Stellen:

1) Du versuchst etwas in UTF-8 zu wandeln. Bist du dir sicher, dass decode gemeint ist und nicht encode ;-)

2) Du beachtest die Codierung der empfangenen Daten nicht. Die sind nämlich "ISO-8859-1"-codiert. Lass dir einfach mal die empfangenen Daten ausgeben und suche danach. Die kann sich natürlich ändern und du musst sie vor dem Umwandeln herausfinden.

Also etwa die folgenden Schritte:
1) Seite herunterladen
2) Codierung rausfinden (bspw. ISO-8859-1)
3) Decodieren der empfangen Daten mit Codec aus 2
4) Codieren der Daten aus 3 in UTF-8

Vielleicht noch ein Hinweis für einen späteren Post: Zeige die ganze Fehlermeldung inklusive des Tracebacks. Hier war es zwar eindeutig, aber manchmal helfen ein paar Zeilen mehr.

Verfasst: Samstag 26. September 2009, 21:12
von cofi
[quote="EyDu"]Da hapert es gleich an ein paar Stellen:
1) Du versuchst etwas in UTF-8 zu wandeln. Bist du dir sicher, dass decode gemeint ist und nicht encode ;-)[/quote]
Na bei dir aber auch *g*

Um das mal zu entwirren: EyDu meint, dass du _sagst_, dass du es als UTF-8 kodierst, aber dass du versuchst etwas, das mit UTF-8 kodiert ist _dekodieren_ willst. Insofern stimmt schon deine Herangehensweise, aber dein Encoding nicht.

Bytes -> decode -> Unicode/String
Unicode/String -> encode -> Bytes

Leonidas' Unicode-Folien solltest du dir vllt anschaun:
http://wiki.python.de/User%20Group%20M% ... folien.pdf

P.S. Leonidas, wenn du das liest, liegen die eventuell auch an einem Ort, dessen URL das Forum nicht zerschiesst?

Verfasst: Samstag 26. September 2009, 22:56
von gfmwm
Vielen Dank für die schnellen Antworten. Im Quelltext-Header von google.de steht "charset='UTF-8'", deshalb dachte ich es würde mit den encoden klappen.

Jetzt habe ich folgende Zeile geändert:

Code: Alles auswählen

res = byt.decode('latin-1')
Und auf einmal funktioniert es. Diese Sache mit dem Kodieren ist wirklich eine Wissenschaft für sich. Schade, dass man sich bei einer Hochsprache wie Python trotzdem damit abquälen muss.

Nochmals Danke.
Dieter

Verfasst: Samstag 26. September 2009, 23:40
von sma
Schaue ich mir http://www.google.de im Browser an, sehe ich, dass im Header UTF-8 steht und auch das HTML selbst sagt UTF-8. Hole ich mir die Seite jedoch mit Python, steht da ISO-8859-1.

Code: Alles auswählen

x = urllib.request.urlopen("http://www.google.de")
print(x.code)
print(x.getheader("content-type"))
content = x.read().decode("iso-8859-1")
Allerdings: Einem XML-Parser sollte man Bytes übergeben müssen, keinen Zeichen, weil XML selbst ja das Encoding kennt (welches UTF-8 ist, wenn nicht anders angegeben). Ich würde vermuten, bei einem HTML-Parser ist es genauso, nur das da der Standard ISO-8859-1 ist.

PS: Google nutzt bereits den HTML-5-DOCTYPE. Nett...

Stefan

Verfasst: Sonntag 27. September 2009, 10:34
von Dav1d
sma hat geschrieben: PS: Google nutzt bereits den HTML-5-DOCTYPE. Nett...

Stefan
den der Internet Explorer nicht kapiert -.-

Verfasst: Sonntag 27. September 2009, 10:38
von cofi
Dav1d hat geschrieben:den der Internet Explorer nicht kapiert -.-
Der hat sich halt schon immer mit Standards schwer getan. Das hatter von der Mutter.

Verfasst: Sonntag 27. September 2009, 10:42
von Dav1d
zum bsp: mit der RICHTIGEN Darstellung von CSS

damit wir nicht ganz vom Thema abkommen, eine Methode um unicode zu kriegen!:

Code: Alles auswählen

urlopen('http://www.google.de')
encoding = f.info()['content-type'].split('charset=')[1]
content = f.read().decode(encoding)
f.close()

Verfasst: Sonntag 27. September 2009, 12:52
von gfmwm
Danke für die zahlreichen Antworten. Das ist also das Endergebnis:

Code: Alles auswählen

from urllib.request import urlopen

url = "http://www.google.de"
req = urlopen(url)
byt = req.read()
enc = req.info()['content-type'].split('charset=')[1]
res = byt.decode(enc)

print(res)
Das funktioniert aber nicht mehr jeder Seite. Ich habe es getestet. Liegt das vielleicht an schlampigen Webmaster die eine falsche Kodierung angeben?

Mfg
Dieter

Verfasst: Sonntag 27. September 2009, 13:07
von cofi
Nein nicht unbedingt. Man muss auch sagen, dass Dav1ds Methode nicht allzu robust ist.

Ungetestet.

Code: Alles auswählen

def get_encoding(response):
    content_header = response.getheader('content-type')
    encoding = content_header.split(';')[-1].strip()
    if encoding.startswith('charset='):
        return encoding[len('charset='):]
    else:
        return None
Anzuwenden auf das `response`-Objekt, dh. in Zeile 7:

Code: Alles auswählen

encoding = get_encoding(req)
Man sollte evtl aber lieber ueber einen echten HTML Parser nachdenken.

Edit: Bugfix, aber immernoch nicht getestet.

Verfasst: Sonntag 27. September 2009, 13:14
von Leonidas
cofi hat geschrieben:Leonidas' Unicode-Folien solltest du dir vllt anschaun:
[wiki]User Group München[/wiki]?action=AttachFile&do=get&target=unicode-folien.pdf

P.S. Leonidas, wenn du das liest, liegen die eventuell auch an einem Ort, dessen URL das Forum nicht zerschiesst?
Also bei mir wird die URL richtig angezeigt (also zumindest deine, die gequotete ist tatsächlich kaputt). Ansonsten liegen die Folien auch noch hier, zusammen mit den Bildern und TeX-Dateien.

Verfasst: Sonntag 27. September 2009, 13:18
von cofi
Leonidas hat geschrieben:Also bei mir wird die URL richtig angezeigt (also zumindest deine, die gequotete ist tatsächlich kaputt)
Ja richtig, BBCode zerschiesst die URL ;) Und der laesst sich leider nur Posting-weit deaktivieren (oder gibt es da ein magisches Tag?) Danke fuer die URL.