Jak mogę korzystać z usługi internetowej WSDL (SOAP) w Pythonie?

124

Chcę używać usługi internetowej opartej na WSDL SOAP w języku Python. Przyjrzałem się kodowi Dive Into Python, ale moduł SOAPpy nie działa pod Pythonem 2.5.

Próbowałem użyć mydlin, które działają częściowo, ale psują się z niektórymi typami (suds.TypeNotFound: Type not found: 'item').

Przyjrzałem się także Client, ale wygląda na to, że nie obsługuje WSDL.

Spojrzałem na ZSI, ale wygląda to na bardzo złożone. Czy ktoś ma do tego przykładowy kod?

WSDL to https://ws.pingdom.com/soap/PingdomAPI.wsdl i działa dobrze z klientem PHP 5 SOAP.

davidmytton
źródło
3
Czy rozważyłbyś zmianę zaakceptowanej odpowiedzi? Obecnie akceptowana odpowiedź to -1, a jest inna odpowiedź z +19. Wiem, że to jest z 2008 roku; Ja tylko sugeruję.
Mark E. Haase
SUDS nie działał, ponieważ nie mógł poprawnie przeanalizować WSDL, ale w przeciwnym razie byłby dobrym wyborem. Więc zmieniłem odpowiedź na tutorial z Dive Into Python, który ma kilka alternatyw. Na marginesie, Pingdom ma teraz interfejs API REST pingdom.com/services/api-documentation-rest z bibliotekami klienta pod adresem blog.pingdom.com/2011/04/11/pingdom-rest-api-wrappers
davidmytton

Odpowiedzi:

49

Polecam przyjrzeć się SUDS

„Suds to lekki klient SOAP Python do korzystania z usług sieci Web”.

Yusufk
źródło
Oddelegowany. Suds nabrał dla mnie natychmiastowego sensu, brak generowania klas, ładuje WSDL na żywo i tworzy obiekt, którego można od razu użyć.
EnigmaCurry
19
Suds ma problem z nieskończoną rekurencją podczas otwierania WSDL z rekurencyjnymi importami. Jest to uważane za błąd blokujący przez Suds, a problem został utworzony ponad 3 lata temu, ale nie został jeszcze naprawiony. fedorahosted.org/suds/ticket/239 To sprawia, że ​​zastanawiam się, czy Suds nadaje się do użytku w 2012 roku?
Buttons840,
2
mydlin wydaje się martwy. Niech żyje SUDS - wydaje się, że to aktywny Fork.
nerdoc
3
To najlepsza odpowiedź, ale jeśli ktoś szuka odpowiedzi, która działa dzisiaj, rozważ Zeep , jak sugerują również nowsze odpowiedzi.
Tobias Feil
25

Istnieje stosunkowo nowa biblioteka, która jest bardzo obiecująca i choć wciąż słabo udokumentowana, wydaje się bardzo czysta i pythonowa : python zeep .

Zobacz także tę odpowiedź jako przykład.

lorenzog
źródło
2
+1 za to. Próbowałem dzisiaj zeep i był zaskakująco łatwy w użyciu. Był w stanie skonsumować i zadzwonić do usługi Soap 1.1 / 1.2 z 3 liniami kodu.
Jagu,
20

Niedawno natknąłem się na ten sam problem. Oto streszczenie mojego rozwiązania:

Potrzebne są podstawowe bloki kodu składowego

Poniżej przedstawiono wymagane podstawowe bloki kodu aplikacji klienckiej

  1. Sekcja żądania sesji: poproś o sesję u dostawcy
  2. Sekcja uwierzytelniania sesji: podaj poświadczenia dostawcy
  3. Sekcja klienta: utwórz klienta
  4. Sekcja Security Header: dodaj nagłówek WS-Security do klienta
  5. Sekcja dotycząca zużycia: w razie potrzeby wykorzystaj dostępne operacje (lub metody)

Jakie moduły potrzebujesz?

Wielu sugerowało użycie modułów Pythona, takich jak urllib2; jednak żaden z modułów nie działa - przynajmniej dla tego konkretnego projektu.

Oto lista modułów, które musisz zdobyć. Przede wszystkim musisz pobrać i zainstalować najnowszą wersję suds z poniższego linku:

pypi.python.org/pypi/suds-jurko/0.4.1.jurko.2

Dodatkowo musisz pobrać i zainstalować moduły żądań i suds_requests odpowiednio z poniższych linków (zastrzeżenie: jestem nowy, aby pisać tutaj, więc na razie nie mogę opublikować więcej niż jednego linku).

pypi.python.org/pypi/requests

pypi.python.org/pypi/suds_requests/0.1

Po pomyślnym pobraniu i zainstalowaniu tych modułów możesz zaczynać.

Kod

Wykonując kroki opisane wcześniej, kod wygląda następująco: Importy:

import logging
from suds.client import Client
from suds.wsse import *
from datetime import timedelta,date,datetime,tzinfo
import requests
from requests.auth import HTTPBasicAuth
import suds_requests

Żądanie sesji i uwierzytelnianie:

username=input('Username:')
password=input('password:')
session = requests.session()
session.auth=(username, password)

Utwórz klienta:

client = Client(WSDL_URL, faults=False, cachingpolicy=1, location=WSDL_URL, transport=suds_requests.RequestsTransport(session))

Dodaj nagłówek WS-Security:

...
addSecurityHeader(client,username,password)
....

def addSecurityHeader(client,username,password):
    security=Security()
    userNameToken=UsernameToken(username,password)
    timeStampToken=Timestamp(validity=600)
    security.tokens.append(userNameToken)
    security.tokens.append(timeStampToken)
    client.set_options(wsse=security)

Należy pamiętać, że ta metoda tworzy nagłówek bezpieczeństwa przedstawiony na rysunku 1. Dlatego implementacja może się różnić w zależności od poprawnego formatu nagłówka zabezpieczeń dostarczonego przez właściciela używanej usługi.

Zużyj odpowiednią metodę (lub operację):

result=client.service.methodName(Inputs)

Rejestrowanie :

Jedną z najlepszych praktyk w takich implementacjach jak ta jest rejestrowanie w celu sprawdzenia, jak przebiega komunikacja. W przypadku wystąpienia problemu ułatwia debugowanie. Poniższy kod wykonuje podstawowe logowanie. Możesz jednak rejestrować wiele innych aspektów komunikacji oprócz tych przedstawionych w kodzie.

logging.basicConfig(level=logging.INFO) 
logging.getLogger('suds.client').setLevel(logging.DEBUG) 
logging.getLogger('suds.transport').setLevel(logging.DEBUG)

Wynik:

Oto wynik w moim przypadku. Zauważ, że serwer zwrócił HTTP 200. Jest to standardowy kod sukcesu dla odpowiedzi żądanie-odpowiedź HTTP.

(200, (collectionNodeLmp){
   timestamp = 2014-12-03 00:00:00-05:00
   nodeLmp[] = 
      (nodeLmp){
         pnodeId = 35010357
         name = "YADKIN"
         mccValue = -0.19
         mlcValue = -0.13
         price = 36.46
         type = "500 KV"
         timestamp = 2014-12-03 01:00:00-05:00
         errorCodeId = 0
      },
      (nodeLmp){
         pnodeId = 33138769
         name = "ZION 1"
         mccValue = -0.18
         mlcValue = -1.86
         price = 34.75
         type = "Aggregate"
         timestamp = 2014-12-03 01:00:00-05:00
         errorCodeId = 0
      },
 })
Teddy Belay
źródło
1
Może warto powiedzieć, że suds_requestinstalacja się nie powiedzie, więc jeśli używasz suds-jurkoforka, możesz zainstalować, suds_requestktóry został dostosowany do pracy z wersją suds jurko:pip install git+https://github.com/chrcoe/suds_requests.git@feature/python3_suds_jurko
errata
7

Obecnie (stan na 2008 r.) Wszystkie biblioteki SOAP dostępne dla Pythona są do niczego. Zalecam unikanie SOAP, jeśli to możliwe. Ostatnim razem, gdy byliśmy zmuszeni do korzystania z usługi sieciowej SOAP z Pythona, napisaliśmy opakowanie w języku C #, które obsługiwało SOAP z jednej strony i wypowiadało COM z drugiej.

Matthew Scouten
źródło
15
Brzmi to jak szalenie skomplikowany sposób korzystania z prostego protokołu opartego na xml i http.
ddaa
1
W 2008 roku była to metoda, która w najmniejszym stopniu odpowiadała naszym potrzebom. Wydaje mi się, że pamiętam, że ta konkretna usługa internetowa była wyjątkowo wybredna, jeśli chodzi o coś, co wszystkie biblioteki Pythona się mylili.
Matthew Scouten
1
2019, python zeep, suds, wciąż podatny na wiele problemów z niekompatybilnością podczas analizowania. Źle utrzymywane dokumenty wsdl spowodują, że te moduły będą rzucać wyjątek jak nieprzerwana petarda.
mootmoot
6

Od czasu do czasu szukam satysfakcjonującej odpowiedzi na to pytanie, ale na razie nie mam szczęścia. Używam soapUI + próśb + pracy fizycznej.

Zrezygnowałem i użyłem Javy ostatnim razem, kiedy musiałem to zrobić, i po prostu zrezygnowałem kilka razy, kiedy ostatnio chciałem to zrobić, ale nie było to konieczne.

Po pomyślnym korzystaniu z biblioteki żądań w zeszłym roku z RESTful API Project Place, przyszło mi do głowy, że może mógłbym po prostu ręcznie przekazać żądania SOAP, które chcę wysłać w podobny sposób.

Okazuje się, że nie jest to zbyt trudne, ale jest czasochłonne i podatne na błędy, zwłaszcza jeśli pola mają niespójne nazwy (ten, nad którym obecnie pracuję, ma „jobId”, „JobId” i „JobID”). Do załadowania używam soapUI WSDL, aby ułatwić wyodrębnianie punktów końcowych itp. i przeprowadzanie ręcznych testów.Jak dotąd miałem szczęście, że nie wpłynęły na mnie zmiany w żadnym używanym przeze mnie WSDL.

Hywel Thomas
źródło
3

To nieprawda, że ​​SOAPpy nie działa z Pythonem 2.5 - działa, chociaż jest bardzo proste i naprawdę bardzo podstawowe. Jeśli chcesz porozmawiać z jakimś bardziej skomplikowanym serwisem internetowym, ZSI jest Twoim jedynym przyjacielem.

Naprawdę przydatne demo, które znalazłem, znajduje się na http://www.ebi.ac.uk/Tools/webservices/tutorials/python - to naprawdę pomogło mi zrozumieć, jak działa ZSI.

zgoda
źródło
1
python setup.py install wyświetla błędy w najnowszej wersji. Najnowsza kopia deweloperska może działać, ale to uciążliwe.
davidmytton
1

SOAPpy jest teraz przestarzałe, AFAIK, zastąpione przez ZSL. To kwestia dyskusyjna, ponieważ nie mogę zmusić żadnego z nich do pracy, a tym bardziej do kompilacji, na Pythonie 2.5 lub Pythonie 2.6

Blaszany Człowiek
źródło
1
#!/usr/bin/python
# -*- coding: utf-8 -*-
# consume_wsdl_soap_ws_pss.py
import logging.config
from pysimplesoap.client import SoapClient

logging.config.dictConfig({
    'version': 1,
    'formatters': {
        'verbose': {
            'format': '%(name)s: %(message)s'
        }
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'formatter': 'verbose',
        },
    },
    'loggers': {
        'pysimplesoap.helpers': {
            'level': 'DEBUG',
            'propagate': True,
            'handlers': ['console'],
        },
    }
})

WSDL_URL = 'http://www.webservicex.net/stockquote.asmx?WSDL'
client = SoapClient(wsdl=WSDL_URL, ns="web", trace=True)
client['AuthHeaderElement'] = {'username': 'someone', 'password': 'nottelling'}

#Discover operations
list_of_services = [service for service in client.services]
print(list_of_services)

#Discover params
method = client.services['StockQuote']

response = client.GetQuote(symbol='GOOG')
print('GetQuote: {}'.format(response['GetQuoteResult']))
W dół strumienia
źródło
biblioteka jest wymieniona tutaj: code.google.com/archive/p/pysimplesoap
Down the Stream
przykładowe dane wyjściowe: ... DEBUG: pysimplesoap.helpers: complexContent / simpleType / element string = string [u'StockQuote '] GetQuote: <StockQuotes><Stock><Symbol>GOOG</Symbol> <Last> 816,13 </Last> <Data> 23/23/2017</Data><Czas>11:41</Godzina><Zmiana>-13.46</Zmień><Otwarte>820.01</Otwarte><Wysoka>822,57</Wysoka> <Niska> 812,26 </Low> <Volume> 1973140 </Volume> <MktCap> 564,29B </MktCap> <PreviousClose> 829,59 </PreviousClose> <PercentageChange> -1,62% </PercentageChange> <AnnRange> 663,28 - 85Range </Aange> <Earns>27.88</Earns><PE>29.28</PE> <Name> Alphabet Inc. </Name> </Stock> </StockQuotes>
Down the Stream
kończy się niepowodzeniem w Pythonie3 w pysimplesoap / client.py: 757 - obiekt „dict” nie ma atrybutu „iteritems”
ierdna
najwyraźniej wersja dostarczana z PIP jest zepsuta. trzeba go zainstalować ręcznie z GIT - to naprawia rzeczy
ierdna
Słuszna uwaga: zobacz ten link: stackoverflow.com/questions/13998492/iteritems-in-python Słuszna „dict.iteritems został usunięty, ponieważ dict.items robi teraz to samo, co dict.iteritems w pythonie 2…”
Down the Stream