SOAP-Anfrage mittels SOAPpy, Fehler kommt zurück

Sockets, TCP/IP, (XML-)RPC und ähnliche Themen gehören in dieses Forum
Antworten
pedesen
User
Beiträge: 7
Registriert: Sonntag 15. Februar 2009, 13:28

Hallo liebe Python-Gemeinde,

erstmal vorweg: eigentlich ist es mir unangenehm, mit dem ersten Post gleich eine sehr ausführliche Frage zu stellen. :oops:
Ich beschäftige mich erst seit kurzem mit Python, und habe nun dieses hilfreiche Forum entdeckt. SOAP begegnet mir auch zum ersten mal, und schon tauchen erste Schwierigkeiten auf.

Ich möchte Daten über die SOAP-Schnittstelle von openligadb.de abrufen. Aber leider bekomme ich einen Fehler zurück. Ich habe die Library SOAPpy importiert, und versuche folgendermaßen an die Daten zu kommen:

Code: Alles auswählen

from SOAPpy import SOAPProxy
url = 'http://www.OpenLigaDB.de/Webservices/Sportsdata.asmx'
n = 'http://msiggi.de/Sportsdata/Webservices'
proxy = SOAPProxy(url,n)
proxy.config.dumpSOAPOut = 1
proxy.config.dumpSOAPIn = 1
print proxy.GetAvailLeagues()
Als Grundlage diente mir dieses Tutorial: http://diveintopython.org/soap_web_serv ... steps.html

soappy sendet nun folgende Anforderung an den Server:

Code: Alles auswählen

*** Outgoing SOAP ******************************************************
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
>
<SOAP-ENV:Body>
<ns1:GetAvailLeagues xmlns:ns1="http://msiggi.de/Sportsdata/Webservices" SOAP-ENC:root="1">
</ns1:GetAvailLeagues>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
************************************************************************
und bekommt folgende Antwort zurück:

Code: Alles auswählen

*** Incoming SOAP ******************************************************
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope
  xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<soap:Body>
  <soap:Fault>
    <faultcode>soap:Client</faultcode>
    <faultstring>Der Wert des HTTP-Headers 'SOAPAction' wurde vom Server nicht erkannt: GetAvailLeagues.</faultstring>
    <detail />
  </soap:Fault>
</soap:Body>
</soap:Envelope>
************************************************************************
Auf openligadb.de existiert ein Beispiel für eine SOAP 1.1-Anforderung und -Antwort. (siehe: http://www.openligadb.de/Webservices/Sp ... ailLeagues)

OpenLigaDB-Beispiel für eine SOAP Anforderung

Code: Alles auswählen

POST /Webservices/Sportsdata.asmx HTTP/1.1
Host: www.openligadb.de
Content-Type: text/xml; charset=utf-8
Content-Length: length
SOAPAction: "http://msiggi.de/Sportsdata/Webservices/GetAvailLeagues"

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetAvailLeagues xmlns="http://msiggi.de/Sportsdata/Webservices" />
  </soap:Body>
</soap:Envelope>

Seh ich es richtig, dass SOAPpy den HTTP-Header - wie er im OpenLigaDB-Beispiel erscheint - gar nicht sendet? Auch die xml ist ganz anders aufgebaut. Ist SOAPpy für Anfragen an OpenLigaDB also unbrauchbar? Oder bin ich da jetzt völlig auf dem Holzweg und hab das SOAP-Prinzip noch nich richtig verstanden?

Es ist für mich alles ein wenig undurchschaubar. Es wäre nett, wenn jemand Rat weiß und mir Tipps geben könnte, wie ich zum Ziel kommen kann. :wink:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Hallo pedesen, willkommen im Forum,

Doch, der Header wird schon gesendet. Aber du hängst dich IMHO sehr an dem formalen auf. Die Frage ist eher: was machst du, was passiert und was erwartest du dass passiert?

Was ist denn der Fehler der zurückkommt? Also nicht vom XML sondern die Python-Fehlermeldung.

Und ja, SOAP und Python ist eine leidige Geschichte, weil SOAP eben ziemlich fürchterlich ist.
Zuletzt geändert von Leonidas am Sonntag 15. Februar 2009, 15:59, insgesamt 1-mal geändert.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
sma
User
Beiträge: 3018
Registriert: Montag 19. November 2007, 19:57
Wohnort: Kiel

Vor kurzem hatte ich mit Webservices experimentiert, war aber genervt, dass ich bei Python erst mehrere Bibliotheken hätte nachinstallieren müssen und bin daher bei Ruby gelandet. Ich kann daher nicht so viel zu SOAPpy sagen.

Dein SOAP-Request sieht okay aus. Die Namen der Namensräume sind bei XML egal, es zählt nur die URI. Beide Beispiele sind geschwätziger als notwendig aber das sollte egal sein.

Aus der Fehlermeldung des Servers rate ich, dass er den HTTP-Header "SOAPAction" erwartet und nicht vorfindet. Ich hätte gedacht, das wäre optional, aber ist es wohl nicht. Ob SOAPpy das bei dir mitschickt, kann ich dir leider nicht sagen.

Wenn ich diesen undokumentierten Mist ähem ich meine den Quelltext von SOAPpy richtig verstehe, kann man als dritten Argument von `SOAPProxy` besagte SOAPAction angeben. Versuche das doch mal.

Ob's klappt und was da überhaupt ausgegeben wird, kann man sehen, wenn man `dumpHeadersOut` in der Konfiguration setzt, sagt mir ein Blick in den Quelltext. Das sollte dir doch weiterhelfen. Ich würde raten, es fehlt der Namensraum. Denn wenn ich den Quelltext richtig verstehe, wird standardmäßig einfach der Methodenname benutzt, wenn die Aktion nicht explizit angegeben wird.

Stefan
pedesen
User
Beiträge: 7
Registriert: Sonntag 15. Februar 2009, 13:28

@Leonidas: den Fehler hab ich gut im xml-code versteckt, sorry. Sieht dann so aus:

Der Wert des HTTP-Headers 'SOAPAction' wurde vom Server nicht erkannt: GetAvailLeagues.

Dieses Problem hab ich aber nun in den Griff bekommen.

@sma: Das gesetzte dumpHeadersOut hat mir Klarheit verschafft. Danke! Folgendermaßen klappts:

Code: Alles auswählen

from SOAPpy import SOAPProxy
url = 'http://www.OpenLigaDB.de/Webservices/Sportsdata.asmx'
n = 'http://msiggi.de/Sportsdata/Webservices'
action = 'http://msiggi.de/Sportsdata/Webservices/GetAvailLeagues'
proxy = SOAPProxy(url,n,action)
#proxy.config.dumpSOAPOut = 1
#proxy.config.dumpSOAPIn = 1
#proxy.config.dumpHeadersOut = 1
print proxy.GetAvailLeaguesResult()
Jetzt bekomme ich anscheinend ein SOAPpy-Objekt mit allen Daten zurück. Mit print ausgegeben sieht das (stark gekürzt) so aus:

Code: Alles auswählen

<SOAPpy.Types.structType GetAvailLeaguesResult at 150895884>:
  {'League':[
    <SOAPpy.Types.structType League at 150917804>:
      {'leagueID': '48', ... , 'leagueShortcut': 'Wilkommen'},
    <SOAPpy.Types.structType League at 150918092>:
      {'leagueID': '50', ... , 'leagueShortcut': 'bl1'}
    ...
Jetzt ist mir allerdings nicht klar, wie ich darauf zugreifen kann. Ich werd es trotzdem mal versuchen.
Wenn ichs geschafft hab, meld ich mich, für Tipps bin ich jedoch jederzeit dankbar :wink:
pedesen
User
Beiträge: 7
Registriert: Sonntag 15. Februar 2009, 13:28

Gut, zugegebenermaßen hab ich echt aus den Augen verloren, was ich eigentlich will. Ich hab jetzt Abstand von GetAvailLeagues genommen.
Was ich will, sind alle Bundesligapaarungen eines bestimmten Spieltags, die ich mit GetMatchdataByGroupLeagueSaison bekomme. Ich bin auch schon ein Stück weitergekommen. Leider taucht schon wieder das nächste Problem auf (siehe unten).

mein Python-Code:

Code: Alles auswählen

from SOAPpy import SOAPProxy
url = 'http://www.OpenLigaDB.de/Webservices/Sportsdata.asmx'
n = 'http://msiggi.de/Sportsdata/Webservices'
action = 'http://msiggi.de/Sportsdata/Webservices/GetMatchdataByGroupLeagueSaison'
proxy = SOAPProxy(url,n,action)
proxy.config.dumpSOAPOut = 1
print proxy.GetMatchdataByGroupLeagueSaison(groupOrderID=20,leagueShortcut='bl1',leagueSaison='2008')
Folgende Anforderung wird an den Server geschickt:

Code: Alles auswählen

<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope
  SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/"
  xmlns:xsi="http://www.w3.org/1999/XMLSchema-instance"
  xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"
  xmlns:xsd="http://www.w3.org/1999/XMLSchema"
>
<SOAP-ENV:Body>
<ns1:GetMatchdataByGroupLeagueSaison xmlns:ns1="http://msiggi.de/Sportsdata/Webservices" SOAP-ENC:root="1">
<leagueSaison xsi:type="xsd:string">2008</leagueSaison>
<groupOrderID xsi:type="xsd:int">20</groupOrderID>
<leagueShortcut xsi:type="xsd:string">bl1</leagueShortcut>
</ns1:GetMatchdataByGroupLeagueSaison>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Das Beispiel von OpenLigaDB für eine SOAP Anforderung:

Code: Alles auswählen

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <GetMatchdataByGroupLeagueSaison xmlns="http://msiggi.de/Sportsdata/Webservices">
      <groupOrderID>int</groupOrderID>
      <leagueShortcut>string</leagueShortcut>
      <leagueSaison>string</leagueSaison>
    </GetMatchdataByGroupLeagueSaison>
  </soap:Body>
</soap:Envelope>
Leider meckert python jetzt:

Code: Alles auswählen

Traceback (most recent call last):
  File "openliga2.py", line 10, in <module>
    print proxy.GetMatchdataByGroupLeagueSaison(groupOrderID=20,leagueShortcut='bl1',leagueSaison='2008')
  File "/var/lib/python-support/python2.5/SOAPpy/Client.py", line 470, in __call__
    return self.__r_call(*args, **kw)
  File "/var/lib/python-support/python2.5/SOAPpy/Client.py", line 492, in __r_call
    self.__hd, self.__ma)
  File "/var/lib/python-support/python2.5/SOAPpy/Client.py", line 406, in __call
    raise p
SOAPpy.Types.faultType: <Fault soap:Server: Die Anforderung konnte vom Server nicht verarbeitet werden. ---> Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt.: >
Wenn ich die beiden xmls vergleiche, siehts doch eigentlich gut aus? woran scheitert es? Ich werde aus der Fehlermeldung nicht schlau. Auch ein Blick in Client.py hilft mir nicht weiter. Ich hab trotzdem das Gefühl, ich bin nah dran :wink:
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Da nutze ich lieber suds:

Code: Alles auswählen

from suds.client import Client
c = Client('http://www.openligadb.de/Webservices/Sportsdata.asmx?WSDL')
res = c.service.GetTeamsByLeagueSaison(leagueShortcut='bl1', leagueSaison='2008')
print res.Team[0].teamName
Analog dazu alle anderen API-Calls, ``GetMatchdataByGroupLeagueSaison`` funktioniert hier ebenfalls ok.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
pedesen
User
Beiträge: 7
Registriert: Sonntag 15. Februar 2009, 13:28

Der Hammer! Vielen Dank!
Antworten