Urllib2 - Autoencode deaktivieren

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
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Hallo Zusammen,

ich versuche aktuell eine einfach Ansteuerung einer REST Schnittstelle via Python zu machen.

Fall:

Ich habe eine Webseite und will bestimmte Personen finden, siehe Beispiel:
http://xyz.de/freunde-finden.html?name=Hübner

Die Schnittstelle nimmt den Name "Hübner" genau so an und würde ihn ohne weiteres verarbeiten jedoch kommt durch den Aufruf von
urllib2.urlopen("http://xyz.de/freunde-finden.html?name=Hübner")
dies nicht an stattdessen wird die Url decodiert da man anscheinend keine Umlaute in die URL packen kann.

Hat jemand dafür vielleicht ne Lösung? Ich hab mehrere Seiten durchforstet jedoch nichts gefunden.

Gruß
Nhat
BlackJack

@nhat: Was heisst das die Schnittstelle nimmt das genau so an? Wie denn? Wie muss das 'ü' kodiert sein? Und in URLs muss man das den regeln für URLs entsprechend kodieren, da dürfen nur ASCII-Zeichen enthalten sein, und davon auch nicht alle.

Und wo bekommst Du überhaupt welchen Fehler? Ich habe das gerade mal ausprobiert und bekomme einen `HTTPError`, und zwar einen 404 weil es die Seite nicht gibt. Das heisst aber auch das die URL trotz dem das man das eigentlich nicht darf, einfach so übertragen wurde wie angegeben. Kein Kodierungsfehler.

Sonstige Anmerkung: Tu Dir selbst einen gefallen und verwende die (externe) `requests`-Bibliothek statt dem `urllib`/`urllib2`-Murks aus der Standardbibliothek.
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Ohje sorry, habe es vollkommen vergessen hinzuschreiben.

Also die Schnittstelle extrahiert die Parameter:

name = Hübner , somit wird dem Datenfeld "name" der Wert "Hübner" zugewiesen, also 1 zu 1 keine Konvertierung nichts.

Aus dem Grund wollte ich eben den Namen auch 1zu1 in die URL schreiben einfach durch Konkatenation in der URL. Es entsteht somit kein Fehler nur die REST-Schnittstelle findet halt keine Treffer da anstatt Hübner -> H%81bner übertragen wird.
Wenn du aber jetzt sagst das sowas unmöglich ist eine raw-Url zu übertragen dann muss ich mir was anderes einfallen lassen.

nhat
BlackJack

@nhat: Bei Deinem Ansatz wird nicht 'H%81bner' übertragen, jedenfalls nicht nach meinen Tests mit `urllib2`. Es sei denn Du hast selber dafür gesorgt das das 'ü' als '%81' kodiert wurde.

`requests` macht das automatisch, das klärt aber immer noch nicht in welcher Zeichensatzkodierung die Gegenseite die Daten erwartet, also ob nun 'H%81bner' oder vielleicht nicht doch 'H%C3%BCbner'.

Keine Konvertierung, wie Du sagst, geht zumindest bei der URL-Kodierung nicht, die muss sein, und eine Ebene darunter muss natürlich auch das 'ü' in irgendeiner Weise kodiert sein.
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Naja ich hab openurl(..) gemacht und danach aus dem Ergebnis mir nochmals die URL ausgeben gelassen und dann war diese eben mit '%81' dargestellt worden. Ich habe vorher mal getestet ob er mir den Namen überhaupt auf der Konsole ausgeben lassen kann indem ich eine einfache Print Anweisung geschrieben habe:

print "Hübner"

da er hierbei nicht das 'ü' kodiert hat bin ich davon ausgegangen das er mir beim Ergebnis das nicht kodiert. Die URL hieß dann nämlich:

http://xyz.de...name=hübner

Sollte ich mal mehrere Kodierungen ausprobieren? Kannst du mir da ggf. verschiedene vorschlagen? Bin nämlich wie du sicherlich gemerkt hast nicht so der python profi. Ich wüsste jetzt nicht auf die schnelle wie ich mehrere Kodierungen auf den Namen anwenden könnte.


Ich habe die REST Schnittstelle nicht geschrieben und bin halt nur davon ausgegangen da diese Umlaute akzeptiert. Im Browser kann ich durch Eingabe von "Hübner" in der Adresszeile nämlich die Daten abrufen. Von daher dachte ich das es so gehen sollte.

Gruß
nhat

Danke für deine Hilfe!
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Mh okay, wenn ich das "ü" per Hand mit "%C3%BC" eingebe dann funktioniert es auch. Wie müsste ich dann die URL preparieren/kodieren damit ich das so erhalte?

Ich geh mal stark davon aus das dies UTF-8 ist jedoch wie kann ich dies auf den String anwenden ohne das Fehler entstehen.
BlackJack

@nhat: Das ist ja interessant. Dann ist in dem Rückgabewert ein anderer Wert als der, der tatsächlich als URL an den Server übertragen wurde. Denn ich hatte direkt im Serverlog nachgesehen und da war es nicht URL-kodiert.

'%C3%BC' ist ein ü erst UTF-8 und dann URL-kodiert. Ich erwähnte ja schon die `requests`-Bibliothek. Die nimmt einem echt viel Arbeit ab und hat eine wesentlich schönere API als die Standardbibliothek. Und wenn man mit Texten arbeitet, dann sollte man Unicode-Objekte und keine (Byte-)Zeichenketten verwenden. Das könnte dann so aussehen:

Code: Alles auswählen

In [5]: r = requests.get('http://localhost/test.htm', params={'name': u'Hübner'})

In [6]: r.url
Out[6]: u'http://localhost/test.htm?name=H%C3%BCbner'
Im Zugriffsprotokoll vom Webserver kommt das auch richtig an:

Code: Alles auswählen

127.0.0.1 - - [25/Mar/2014:12:43:44 +0100] "GET /test.htm?name=H%C3%BCbner HTTP/1.1" 404 442 "-" "python-requests/1.1.0 CPython/2.7.1+ Linux/2.6.38-15-generic"
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Sieht schon mal super gut aus. Kannst du mir vielleicht noch sagen wie ich den Namen dann dynamisch festlegen könnte?

r = requests.get('http://localhost/test.htm', params={'name': u'var'}) #geht leider nicht

und mit:

var = unicode(var)
oder var = var.decode('UTF-8')

geht auch nicht
BlackJack

@nhat: Das kommt halt darauf an was `var` ist. Wenn es eine (Byte-)Zeichenkette ist, dann muss man sie dekodieren. Mit welcher Kodierung hängt davon ab mit welcher Kodierung diese Daten kodiert sind. Das muss man selber wissen.
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Das ist ne gute Frage :)

Ich bekomme:
"H%FCbner" ausgegeben
ich geh mal davon aus das dies "ascii" ist.
BlackJack

@nhat: *Da* sind jetzt nur ASCII-Zeichen enthalten, das ist ja aber auch URL-kodiert. Wenn man des dekodiert hat (`urlparse.unquote()`), muss man die resultierenden Bytes, die nicht mehr nur ASCII-Werte enthalten in ein Unicode-Objekt dekodieren. Das könnte Latin-1 a.k.a. ISO-8859-1 sein, oder CP1250, oder irgend eine andere Kodierung die den Bytewert 252 auf den Buchstaben ü abbildet.

Code: Alles auswählen

In [17]: urlparse.unquote('H%FCbner').decode('latin1')
Out[17]: u'H\xfcbner'

In [18]: print urlparse.unquote('H%FCbner').decode('latin1')
Hübner
nhat
User
Beiträge: 7
Registriert: Montag 24. März 2014, 16:57

Danke, ich glaub ich habs jetzt verstanden :P
Antworten