Urllib2 in python 3 installieren?

Probleme bei der Installation?
Antworten
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Ich habe ein fertiges Skript, welches ich ausprobieren möchte bei dem urrlib2 verwendet wird.

Wenn ich es ausführen will, kommt aber eine Fehlermeldung.
File "C:\............py", line 2, in <module>
import urllib2
ImportError: No module named 'urllib2'
Deswegen versuche ich es mithilfe von pip zu installieren, aber dabei kommt die Meldung:
pip install urllib2
Downloading/unpacking urllib2
Real name of requirement urllib2 is urllib3
Could not find any downloads that satisfy the requirement urllib2
Cleaning up...
No distributions at all found for urllib2
Also wo liegt der Fehler? Angeblich ist das Skript schon in Python3 geschrieben.
BlackJack

@Serpens66: `urllib2` ist ein Modul aus der Standardbibliothek von Python 2. Der Inhalt von den Modulen `urllib` und `urllib2` aus Python 2 ist in der Python 3 Standardbibliothek umorganisiert worden, das heisst die Inhalte sollten noch vorhanden sein, heissen aber anders. Darum kommt mir das etwas merkwürdig vor, dass ein für Python 3 geschriebenes Programm noch `urllib2` importieren möchte.

Steht denn in der Dokumentation von dem Programm irgendetwas zu Abhängigkeiten die man vorher installieren muss? Eventuell vielleicht das `future`-Package?
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

danke für die Erklärung.
Aus irgendeinem Grund dachte ich es sei Python3, aber dann ist es wohl doch Python2... (gibt keine Angabe zur Version)


Wie aufwendig wird es, das in Python3 umzuschreiben? Kann ich das sogar schon selbst, indem ich irgendeine Hilfsseite zur Hilfe nehme?
es geht um folgendes Skript:
https://github.com/mikexine/ArbitrageBo ... /PyRock.py
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Das Script ist aus vielen Gründen einfach so grausam, dass man es nicht umschreibem, sondern *neu* schreiben sollte :twisted:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
BlackJack

@Serpens66: Wie gesagt, die Module `urllib` und `urllib2` wurden in Python 3 umstrukturiert. Die Funktionalität ist noch da, nur eben an anderer Stelle in der Standardbibliothek. Das kann man also anpassen. Dann bleibt nur noch die Frage ob da irgendwelche Byte- vs. Unicode-String-Unterschiede zum tragen kommen. Dem könnte man mit dem `requests`-Modul aus dem Weg gehen. Das ist reines Python, lässt sich also mit `pip` installieren, und es bietet a) eine schönere API als `urllib*` und b) ist die API unter Python 2 und Python 3 gleich.

Das Modul ist ziemlich hässlich. Die ganzen Code-Wiederholungen in den Methoden, das nackte ``except:`` was dazu führt das bei jeglichen Ausnahme so behandelt wird das einfach `None` zurückgegeben wird, das in ein paar Methoden aus nicht wirklich ersichtlichen Gründen neue Attribute eingeführt werden, die komische Formatierung der Kommentare die eigentlich DocStrings sein sollten, die Namensschreibweisen die sich nicht an Python-Konventionen halten…

Edit: Wobei die Kommentare auch als DocStrings nicht so viel besser wären, denn die sind alle so verdammt offensichtlich das man sie auch einfach weglassen könnte.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

ja, request hab ich schon ohne probleme installiert :)

Leider ist dieses anscheinend schlechte Skritp, das einzige was ich (zumindest für diese bitcoinbörse) als Vorbild habe.
Habe schon github durchsucht, ansonsten gibt es nur noch was mit ".js" als Dateiendung, was vermutlich JavaScript ist. Vermutlich kann man ein Javascript sogar mit Python kombinieren, aber ich schätze mal, dass das soviel Wissen voraussetzt, dass es einfacher wäre, das Skript von vorneherein in Python zu schreiben :D

Wäre einer von euch bereit mir dieses Skript "in schön" und Python 3 zu schreiben? Oder irgendeine Hilfsseite, mit dessen Hilfe ich es umwandeln kann, ohne vorher Python2 lernen zu müssen?

EDIT:

habe grade sowas gefunden:
https://docs.python.org/2/glossary.html#term-to3
hilft das in dem fall?

edit2:
sry dass ich soviel editiere, wollte keinen doppelpost machen. ^^
Also ich habe jetzt mal 2to3 auf das Skript angewandt und anstelle von urllib2 stehen da nun auch die schon erwähnten anderen Module. Leider tritt trotzdem ein Fehler bei er ausführung auf. Ich schau mir den mal an und gucke, ob ich ihn selbst bereinigen kann. Falls nicht, schreibe ich ihn hier noch als edit3 mit rein ;)
Zuletzt geändert von Serpens66 am Freitag 19. Dezember 2014, 23:32, insgesamt 1-mal geändert.
BlackJack

@Serpens66: So gross sind die Unterschiede zwischen Python 2 und 3 dann doch nicht das man da von „Python2 lernen müssen” sprechen kann. Und das Modul ist ja nun nicht wirklich kompliziert. Da ist nichts abgefahrenes drin, kein komplexer Algorithmus, eigentlich ja nur ein paar Anfragen an eine Web-API und Python-Grunddatentypen.

Du kannst 2to3 ja einfach mal auf den Quelltext anwenden und Dir die Veränderungen anschauen. Das dürften eigentlich nur die Änderungen sein die sich durch das Verschieben des Inhalts von `urllib` und `urllib2` ergeben haben. Und dann ist halt noch die Frage ob die Änderung von den literalen Zeichenketten von Bytes nach Unicode Änderungen erforderlich machen. Mit Bytes vs. Zeichenketten und dem Thema Kodierungen muss man sich als Programmierer heutzutage sowieso mal gründlich auseinandersetzen. Das ist ein Thema was wahrscheinlich nicht einmal mehr Leute in rein englischsprachigen Umgebungen ignorieren können.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

hmmm um die Sache zu beschleunigen Frage ich doch nochmal hier wegen dem Fehler nach:

Der Fehler ist:
File "C:\.............\PyRock.py", line 117, in MarketData
MkData = json.loads(ResponseTrt.read())
File "C:\Python34\lib\json\__init__.py", line 312, in loads
s.__class__.__name__))
TypeError: the JSON object must be str, not 'bytes'
Gut, die Fehlermeldung sagt mir also, dass dort kein string wie erwartet, sondern "bytes" übergeben werden.
Du schreibst ja schon, dass so ein Fehler bei der Umwandlung von 2 zu 3 auftreten kann.

Wie löse ich das? Bzw. hast du eine zu empfehlende Infoseite diesbezüglich parat?
BlackJack

@Serpens66: Der Klassiker ist: The Absolute Minimum Every Software Developer Absolutely, Positively Must Know About Unicode and Character Sets (No Excuses!).

Ansonsten kann ich nochmal `requests` wärmstens empfehlen, das kümmert sich automatisch um das parsen einer JSON-Antwort vom Server und stellt das Ergebnis als Attribut auf dem Antwortobjekt zur Verfügung.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

BlackJack hat geschrieben: Ansonsten kann ich nochmal `requests` wärmstens empfehlen, das kümmert sich automatisch um das parsen einer JSON-Antwort vom Server und stellt das Ergebnis als Attribut auf dem Antwortobjekt zur Verfügung.
Ist das so ungefähr richtig gelöst mit requests? (die alten funktionen hab ich auskommentiert erstmal drin gelassen, zum Vergleich vorher, nachher und falls ich sie nochmal brauchen sollte)

Code: Alles auswählen

    def MarketData(self, fund):
        #self.fund=fund
        #Url = "https://www.therock.com/api/ticker/"+self.fund
        #ResponseTrt = urllib.request.urlopen(Url)
        #MkData = json.loads(ResponseTrt.read())
		data = {'fund': fund}
		MkData = requests.post('https://www.therock.com/api/ticker/', data=fund).json()
        return MkData
Ich bekomme leider den Fehler:
data = {'fund': fund}
^
TabError: inconsistent use of tabs and spaces in indentation
Den Fehler hatte ich schonmal und der Grund war, wie es in der fehlermeldung ja auch heißt, dass ich zuviel/zu wenige Leerzeichen verwendet habe.
Allerdings komme ich trotz Verwendung des Notepad++ Editors überhaupt nicht mit diesen Leerzeichen zurecht ?! Es ist eigentlich alles genau gleich aingerückt und auch genau so weit, wie es vorher der Fall war. (die meisten Probleme mit Leerzeichen habe ich, wenn ich etwas mit Copy Paste einfüge, dann gibts die Fehlermeldung oft, obwohl ich manuell durch hinzufügen von Leerzeichen, alles aufdieselbe Höhe gebracht habe... )
Im Notepad++ gibt es ja links neben den Code solche "+" und "-" zum auf und zuklappen von zusammengehörenden Abschnitten. Daran kann man ja schonmal gut erkennen, ob alles richtig eingerückt ist. Unter "data=..." und über "MkData=..." ist da schon so ein kleiner Strich. Aber kein + oder -. Dieser scheint auch irgendwie Teilabschnitte zu kennzeichnen.. Aber keine Ahnung, wie ich das nun bereinigen kann.

Das letzte mal hatte ich so einen Fehler bei:

Code: Alles auswählen

				    if GewinnEurBtcXvnGegenUhrzeigersinn < 0:
		                     print("KEINE Gewinnmöglichkeiten zurzeit \n")	
Ich hatte in der print Zeile zuvor einfach nur, nach Konvention, 4 Leerzeichen zugefügt, also dass es 4 Leerezeichen weiter rechts steht, als der if Befehl. Aber das klappte nicht. Letzlich sind es jetzt 9 Leerzeichen und nur so klappt es. Warum klappt es nicht mit 4 und warum gerade 9?

EDIT
Ich sehe gerade nach dem posten: Hier sehen die Einrückungen völlig anders aus, als in meinem Notepad++ ?!
Beim ersten Code sieht es hier ja so aus, als seien meine Befehle weiter eingerückt, als die Kommentare davor... in Notepad++ sind diese aber genau gleich eingerückt... Meine Vermutung ist nun, dass Notepad mir das ganze irgendwie falsch anzeigt und es eig so aussieht wo hier, und daher der Fehler...
Beim zweiten Code mit dem if Befehl... das sieht sowieso völlig anders aus :D im Notepad++ sieht es wie beschrieben aus, als 9 Leerzeichen Einrückung.

Habe nun den obigen Code mit häufigem entfernen von LEerzeichen, wieder zufügen und Absätze zufügen+entfernen iwie dazu gekriegt, dass dieser Strich auf der linken Seite weggegangen ist. Nun sieht es im Notepad so aus, als wäre der return Befehl 8 Leerzeichen von MkData aus gesehen nach rechts gerückt... merkwürdig.... trotzdem ist die Fehlermeldung über " inconsistent use of tabs and spaces in indentation" immernoch dieselbe... ich gebs auf...
Daher nun meine Frage: Was läuft in Notepad++ falsch???
Sirius3
User
Beiträge: 17749
Registriert: Sonntag 21. Oktober 2012, 17:20

@Serpens66: Bei Notepad++ gibt es unter Einstellungen, dass die Tab-Weite 4 Zeichen ist und er statt Tabs Leerzeichen verwenden soll. Wenn Du schon Dateien hast, wo Tabs und Leerzeichen gemischt sind, gibt es unter Bearbeiten den Punkt "Nicht druckbare Zeichen" -> "Tabulatoren in Leerzeichen umwandeln".
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

@Sirius3:
Vielen dank, Problem gelöst :)


Nun also zu requests. Wäre ja zu schön gewesen, wenn ich es auf anhieb richtig gemacht hätte :D Der Code ist immernoch derselbe wie oben nur eben mit der richtigen Anzahl an Leerzeichen.
Die Fehlermeldung lautet nun:
File "C:\............\PyRock.py", line 120, in MarketData
MkData = requests.post('https://www.therock.com/api/ticker/', data=fund).json()
File "C:\Python34\............\models.py", line 793, in json
return json.loads(self.text, **kwargs)
File "C:\Python34\............\__init__.py", line 318, in loads
return _default_decoder.decode(s)
File "C:\Python34\lib\json\decoder.py", line 343, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "C:\Python34\lib\json\decoder.py", line 361, in raw_decode
raise ValueError(errmsg("Expecting value", s, err.value)) from None
ValueError: Expecting value: line 1 column 1 (char 0)
Warum habe ich den Code so geschrieben? Weil ich bereits ein Beispielskript für die Börse Kraken.com habe und dort wird ebenfalls requests verwendet, eben genau in der Form, wie ich es nun auch hier versucht habe.
Liegt es am json?

in der API Doku von Therock steht
The request is done by the standard HTTP GET/POST methods, in return you get a JSON object.
It is important to set the request Content-Type to 'application/json' in the HTTP Header.
Habe ich das nicht beachtet?
BlackJack

@Serpens66: Anscheinend nicht. Und wahrscheinlich wirst Du auch das JSON selber erzeugen müssen und nicht ein Wörterbuch übergeben.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

hm habe es jetzt auf drei arten probiert, wobei ich noch nicht verstanden habe, was der unterschied zwischen params und data in request ist und ob ich "json.dumps" brauche oder nicht... Ich nutze das hier um requests zu verstehen: http://de.python-requests.org/de/latest ... twortdaten
Nun sollte ich die API Anforderungen bezüglich dem header erfüllt haben.

Code: Alles auswählen

    fund= "BTCEUR"
    url = "https://www.therock.com/api/ticker/"
    payload = {'fund': fund}
    header = {'content-type': 'application/json'}
    r = requests.post(url, data=json.dumps(payload), headers=header)
    #r = requests.post(url, params=json.dumps(payload), headers=header)
    #r = requests.post(url, params=payload, headers=header)
    print("von therock \n {0}\n".format(r))
Die print Ausgabe liefert bei allen drei Möglichkeiten von r :
<Response [200]>
In der requests doku steht was von Status Codes... aber nicht was sie bedeuten. Aber daraus würde ich mal folgern, dass immer "200" zurückgeliefert wird, wenn alles okay ist. Das heißt diese Print ausgabe ist nichts besonders...
Nur ist es ja nicht das, was ich haben will :D

Auf der API Seite https://www.therock.com/en/pages/api steht, dass eigentlich folgendes zurückgegeben werden sollte:
Returns:
errorCode - "OK" on success, "ERROR" on failure
symbol - string representation of the specified fund
bid - best bid value of fund_name
ask - best ask value of fund_name
Warum wird stattdessen diese 200 ausgegeben?
BlackJack

@Serpens: `params` werden in der URL übergeben und `data` wird beim Request im Body der Anfrage gesendet. Wie das genau funktioniert und was die numerischen Codes bedeuten kann man in der HTTP-Spezifikation nachlesen. Ich sehe gerade das dieses Jahr da mal ein neue RFCs zu erschienen sind die die von 1999 ablösen: RFC 7230 und folgende. In RFC 2731, Abschnitt 6 werden die Status-Codes behandelt.

Wenn das was von der API beschrieben zurückgegen wird dann *muss* der Code 200 (oder ein anderer „alles in Ordnung”-Code) sein, denn nur dann hat der Webserver ja auch ein JSON-Dokument ausgeliefert das der Beschreibung der Rückgabe in der API-Dokumentation entspricht. Allerdings hätte ich hier einen 404 erwartet denn die URL die Du da abrufst gibt es laut API-Dokumentation nicht. Laut der ist der `fund_name` Teil der Pfadangabe der URL und wird nicht als URL-Parameter oder im Body der Anfrage gesendet. Die übrigens auch eine 'GET'- und keine 'POST'-Anfrage sein soll.

Also letztendlich eine ganz normale 'GET'-Anfrage: https://www.therock.com/api/ticker/BTCEUR

Liefert bei mir:

Code: Alles auswählen

{
    "result": [
        {
            "symbol": "BTCEUR",
            "bid": "266.88",
            "ask": "268.33",
            "last": "267.57",
            "volume": "18235.61",
            "volume_traded": "67.85",
            "open": "273.00",
            "high": "274.29",
            "low": "265.18",
            "close": "265.68"
        }
    ]
}
Interessanterweise ohne `errorCode` wie die API-Dokumentation verspricht.
Serpens66
User
Beiträge: 259
Registriert: Montag 15. Dezember 2014, 00:31

Super, vielen dank :)

Hat ne Weile gedauert, bis ich gemerkt habe, dass die Ergebnisausgabe aus einem dictionary, dann Liste und dann wieder dictionary besteht und ich demnach response['result'][0]['ask'] verwenden muss, wenn ich den ask wert haben will, aber ich habs geschafft :)

Dann würde ich sagen ist das Problem dieses Threads erstmal gelöst :)
Antworten