Tuple aus Dictionaries in einem String parsen

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
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

Hallo,

ich will in einem Python-Script mit einem PHP-Script auf einem Webserver Daten austauschen. Ich dachte mir, am einfachsten wäre es, wenn ich im PHP-Script die Daten so aufbereite das ich sie in Python einfach in eine Variable laden kann. Ich habe mir also einen String im PHP-Script gebaut, der in Python einem tuple aus dicts entspricht und diesen PHP-String dann per printf (über http) an das Python-Script verschickt.

In Python kommt der String auch klaglos an und sieht so aus:

Code: Alles auswählen

print(rcvData)
"({'id':507,'name':'test'},{'id':796,'name':'xyz'},{'id':13,'name':'Ich bin ein Name'})"
Die Variable "rcvData" hat den Type String und jetzt kommt mein Problem, wie kann ich das einfach in eine Variable laden, die dann ein Tuple aus Dictionaries ist?

Wenn ich den empfangenen String nehme und ihn in den Quellcode packe, z.B.:

Code: Alles auswählen

t = ({'id':507,'name':'test'},{'id':796,'name':'xyz'},{'id':13,'name':'Ich bin ein Name'})
Dann ist "t" vom Type Tuple und enthält Dicts.

Falls meine Formatierung des Strings in PHP unglücklich ist, kann ich das auch problemlos ändern, bin für jeden Hinweis/Tipp dankbar!

Hier mein Python-Script (Minimalbeispiel):

Code: Alles auswählen

#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
import urllib2, urllib

trxData=[('one','1'),('two','2')]
trxData=urllib.urlencode(trxData)
path='http://localhost/py.php'
request=urllib2.Request(path, trxData)

response=urllib2.urlopen(request)
rcvData = response.read()
print(rcvData)
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Hallo und willkommen im Forum!

Schau dir mal das json-Modul an, das sollte dein Problem lösen.
Das Leben ist wie ein Tennisball.
BlackJack

@lexaiden: Du solltest nicht anfangen selber Formate zu erfinden, oder sprachspezifische zusammen zu basteln. Für so etwas bietet sich zum Beispiel JSON an. Bei Python gibt es dafür das `json`-Modul in der Standardbibliothek und bei PHP gibt es sicher auch etwas, denn JSON ist aus der Webentwicklung heutzutage ja nicht mehr wegzudenken.

Edit: http://php.net/manual/en/book.json.php
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

Hmmmm, stimmt, da gabs ja noch JSON *ditsch*. Muss leider auch noch gestehen ich hab es auch schon mal verwendet - ist allerdings schon etwas her. Naja, Wald, Bäume usw. - verstehste? :roll:

Danke Jungs!

Werde es dann mit JSON machen, das hat nicht mehr Overhead als meine angedachte Lösung, wenn ich das so Vergleiche. Aber rein Interesse halber, wäre mein Ansatz da oben - ohne jetzt ein riesen Fass (Schleifen, etc.) auf zu machen - lösbar?
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

lexaiden hat geschrieben:Aber rein Interesse halber, wäre mein Ansatz da oben - ohne jetzt ein riesen Fass (Schleifen, etc.) auf zu machen - lösbar?

Code: Alles auswählen

import ast
ast.literal_eval(dein_string)
Aber wie gesagt: Der übliche und dringendst zu empfehlende Weg ist JSON, denn JSON nutzt z.B. eine einheitliche Schreibweise für Wahrheitswerte (true vs. True vs. TRUE) oder Nullzeiger (NULL vs. null vs. None). Es ist eben einfach ein festes Format und tut auch nicht weh.
BlackJack

@lexaiden: Auf der Python-Seite würde ich einen Blick in das requests-Modul werfen. Das ist eine wesentlich schönere API über `urllib` & Co aus der Standardbibliothek:

Code: Alles auswählen

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import requests

def main():
    response = requests.get(
        'http://localhost/py.php', params={'one': '1', 'two': '2'}
    )
    received_data = response.json()
    print(received_data)


if __name__ == '__main__':
    main()
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

@snafu
Das "ast.literal_eval" hab ich gestern getestet und es hat nicht funktioniert, jetzt gerade nochmal getestet und es geht. Möchte mal wissen was ich gestern anders gemacht hab an 'nem Zweizeiler :? , den alten Codeschnipsel hab ich leider nicht behalten. Danke auf alle Fälle.

@BlackJack
Das sieht deutlich schicker aus, ich les es mir mal durch, Danke.
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

Also JSON Daten vom PHP-Script aus an das Python-Script senden klappt wunderbar, wollte jetzt auch die Daten vom Python-Script zum PHP-Script mit JSON kodieren, aber das will nicht.

Ich hab mir eine Klasse gemacht, die sämtliche Kommunikation beinhalten soll, angefangen hab ich jetzt mit dem Login. Die Parameter "user" und "password" kommen von der GUI, diese sollen jetzt mit JSON kodiert an das PHP-Script geschickt werden, aber dort kommt nichts an. Wenn ich die JSON kodierung weglasse, kommen die Daten einwandfrei bei PHP an.

Code: Alles auswählen

import requests
import json
# from PyQt4 import QtGui, QtCore  # old imports
from python_qt_binding import QtGui, QtCore  # @UnresolvedImport @UnusedImport
from satConstances import * # @UnusedWildImport

class satCom:
    def __init__(self):
        self.dataPost = {"user" : "",
                         "password" : "",
                         "phpSessionID" : "",
                         "phpSessionTimeout" : 0,
                         "loggedIn" : False,
                         "request":""}

    def __del__(self):
        pass

    def checkLogin(self, user, password):
        self.dataPost["user"] = user
        self.dataPost["password"] = password
        self.dataPost["request"] = ("checkLogin",)

        print("\n### json.dumps(self.dataPost)") # debug
        print(json.dumps(self.dataPost)) # debug

        retval = requests.post(url, data=json.dumps(self.dataPost), verify=pemFile)

        print("\n### retval.text - mit json") # debug
        print(retval.text) # debug
        #retval.json() # debug

        print("\n### self.dataPost") # debug
        print(self.dataPost) # debug

        retval = requests.post(url, data=self.dataPost, verify=pemFile)

        print("\n### retval.text - ohne json") # debug
        print(retval.text) # debug
        #retval.json() # debug

        if retval["phpSessionID"] > 0:
            self.phpSessionID = retval["phpSessionID"]
            self.phpSessionTimeout = retval["phpSessionTimeout"]
            self.loggedIn = True

Hier mal die Ausgabe auf der Python console (Die Zeilen mit einem ">" davor ist quasi die Ausgabe von PHP):

Code: Alles auswählen

### json.dumps(self.dataPost)
{"loggedIn": false, "phpSessionTimeout": 0, "request": ["checkLogin"], "phpSessionID": "", "user": "", "password": ""}

### retval.text - mit json
>hallo
>Array
>(
>)
>"Kein Benutzer\/Passwort \u00fcbermittelt"

### self.dataPost
{'loggedIn': False, 'phpSessionTimeout': 0, 'request': ('checkLogin',), 'phpSessionID': '', 'user': u'', 'password': u''}

### retval.text - ohne json
>hallo
>Array
>(
>    [loggedIn] => False
>    [phpSessionTimeout] => 0
>    [request] => checkLogin
>    [phpSessionID] => 
>    [user] => 
>    [password] => 
>)
>"Benutzer nicht in DB gefunden,: 0"
Im PHP-Script steht gerade (unteranderem) zu debug Zwecken das:

Code: Alles auswählen

echo "hallo\n";
print_r($_POST);
...daher das "Hallo" in der Ausgabe ;-)

Kann mir mal bitte wer 'nen Tipp geben, warum keine POST Daten gesendet werden, wenn diese JSON kodiert sind? Ich finde eigentlich das mein Code ziemlich genau dem entspricht, was die Doku sagt: http://de.python-requests.org/de/latest ... rte-header Mal davon abgesehen, das ich keinen eigenen Header nutze. Aber auch das habe ich schon probiert und es bringt gar nix.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@lexaiden: woher soll PHP bitte schön wissen, wie Deine POST-Daten kodiert sind!? Wenn Du irgendeine beliebige Byte-Folge schickst, kann ja nicht auf wundersame Weise der Computer raten, wie Du meinst, dass es richtig wäre.
Raw-Daten nehmen:

Code: Alles auswählen

$data = file_get_contents('php://input'); 
und selbst decodieren.
lexaiden
User
Beiträge: 16
Registriert: Montag 15. Juli 2013, 22:11

Danke Sirius3, das war der entscheidende Tipp.

So in Python

Code: Alles auswählen

retval = requests.post(url, data={"json":json.dumps(self.dataPost)}, verify=pemFile)
Dann gehts so in PHP

Code: Alles auswählen

$data = json_decode($_POST["json"]);
print_r($data);
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@lexaiden: ̣... und verpackst Deine Daten gleich zweimal. Die saubere Lösung steht ja schon in Deiner verlinkten Doku. Setze den richtigen »Content-Type« und parse in Deinem PHP-Skript je nach »Content-Type« die POST Daten.
Antworten