urlopen(url).read() in Python3

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
gfmwm
User
Beiträge: 8
Registriert: Samstag 26. September 2009, 18:35

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
Zuletzt geändert von gfmwm am Sonntag 27. September 2009, 12:13, insgesamt 1-mal geändert.
[code]print(''.join(map(lambda c:chr(33+((ord(c)-33+47)%94)),[x for x in 'p{{/*~&#/qp$t/p#t/qt{~}v/%~/&$/PPP'])).replace('^',' '))[/code]
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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.
Das Leben ist wie ein Tennisball.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

[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?
gfmwm
User
Beiträge: 8
Registriert: Samstag 26. September 2009, 18:35

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
Zuletzt geändert von gfmwm am Sonntag 27. September 2009, 12:14, insgesamt 1-mal geändert.
[code]print(''.join(map(lambda c:chr(33+((ord(c)-33+47)%94)),[x for x in 'p{{/*~&#/qp$t/p#t/qt{~}v/%~/&$/PPP'])).replace('^',' '))[/code]
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

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
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

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

Stefan
den der Internet Explorer nicht kapiert -.-
the more they change the more they stay the same
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Dav1d hat geschrieben:den der Internet Explorer nicht kapiert -.-
Der hat sich halt schon immer mit Standards schwer getan. Das hatter von der Mutter.
Dav1d
User
Beiträge: 1437
Registriert: Donnerstag 30. Juli 2009, 12:03
Kontaktdaten:

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()
the more they change the more they stay the same
gfmwm
User
Beiträge: 8
Registriert: Samstag 26. September 2009, 18:35

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
[code]print(''.join(map(lambda c:chr(33+((ord(c)-33+47)%94)),[x for x in 'p{{/*~&#/qp$t/p#t/qt{~}v/%~/&$/PPP'])).replace('^',' '))[/code]
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
Zuletzt geändert von cofi am Sonntag 27. September 2009, 13:14, insgesamt 1-mal geändert.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

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.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

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.
Antworten