Come posso utilizzare un servizio Web WSDL (SOAP) in Python?


124

Voglio usare un servizio web basato su SOAP WSDL in Python. Ho esaminato il codice Dive Into Python ma il modulo SOAPpy non funziona con Python 2.5.

Ho provato a utilizzare la schiuma che funziona in parte, ma si rompe con alcuni tipi (suds.TypeNotFound: Type not found: 'item').

Ho anche esaminato il client, ma non sembra supportare WSDL.

E ho esaminato ZSI ma sembra molto complesso. Qualcuno ha qualche codice di esempio per questo?

Il WSDL è https://ws.pingdom.com/soap/PingdomAPI.wsdl e funziona bene con il client SOAP PHP 5.


3
Prenderesti in considerazione di cambiare la tua risposta accettata? La risposta attualmente accettata è -1 e c'è un'altra risposta con +19. So che è del 2008; Sto solo suggerendo.
Mark E. Haase

SUDS non ha funzionato in quanto non potrebbe analizzare correttamente il WSDL, ma altrimenti sarebbe una buona scelta. Quindi ho cambiato la risposta a un tutorial di Dive Into Python che ha alcune alternative. Come nota a margine, Pingdom ora ha un'API REST pingdom.com/services/api-documentation-rest con le librerie client su blog.pingdom.com/2011/04/11/pingdom-rest-api-wrappers
davidmytton

Risposte:


49

Ti consiglierei di dare un'occhiata a SUDS

"Suds è un client python SOAP leggero per l'utilizzo di servizi Web".


Distaccato. Suds ha avuto immediatamente senso per me, nessuna generazione di classi, carica il WSDL dal vivo e crea un oggetto che puoi utilizzare immediatamente da esso.
EnigmaCurry

19
Suds ha un problema di ricorsione infinita durante l'apertura di WSDL con importazioni ricorsive. Questo è considerato un bug di blocco da Suds e il problema è stato creato più di 3 anni fa, ma non è stato ancora risolto. fedorahosted.org/suds/ticket/239 Mi chiedo se Suds è adatto per l'uso nel 2012?
Pulsanti840

2
la schiuma sembra morta. Lunga vita a SUDS - questo sembra essere il Fork attivo.
nerdoc

3
Questa è la risposta migliore, ma se qualcuno sta cercando una risposta che funzioni oggi, considera Zeep , come suggeriscono anche le risposte più recenti.
Tobias Feil

25

Esiste una libreria relativamente nuova che è molto promettente e sebbene ancora scarsamente documentata, sembra molto pulita e pitonica: python zeep .

Vedi anche questa risposta per un esempio.


2
+1 per questo. Oggi ho provato zeep ed è stato sorprendentemente facile da usare. È stato in grado di utilizzare e chiamare un servizio Soap 1.1 / 1.2 con 3 righe di codice.
Jagu

20

Recentemente mi sono imbattuto nello stesso problema. Ecco la sinossi della mia soluzione:

Blocchi di codice costituenti di base necessari

Di seguito sono riportati i blocchi di codice di base obbligatori dell'applicazione client

  1. Sezione richiesta sessione: richiedi una sessione con il provider
  2. Sezione di autenticazione della sessione: fornire le credenziali al provider
  3. Sezione client: crea il client
  4. Sezione intestazione sicurezza: aggiungi l'intestazione WS-Security al client
  5. Sezione Consumo: consuma le operazioni (o metodi) disponibili secondo necessità

Di quali moduli hai bisogno?

Molti hanno suggerito di utilizzare moduli Python come urllib2; tuttavia, nessuno dei moduli funziona, almeno per questo particolare progetto.

Quindi, ecco l'elenco dei moduli che devi ottenere. Prima di tutto, devi scaricare e installare l'ultima versione di suds dal seguente link:

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

Inoltre, è necessario scaricare e installare le richieste e i moduli suds_requests rispettivamente dai seguenti link (disclaimer: sono nuovo a postare qui, quindi non posso pubblicare più di un link per ora).

pypi.python.org/pypi/requests

pypi.python.org/pypi/suds_requests/0.1

Dopo aver scaricato e installato con successo questi moduli, sei a posto.

Il codice

Seguendo i passaggi descritti in precedenza, il codice è simile al seguente: Imports:

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

Richiesta di sessione e autenticazione:

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

Crea il cliente:

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

Aggiungi intestazione 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)

Si noti che questo metodo crea l'intestazione di sicurezza rappresentata in Fig.1. Pertanto, l'implementazione può variare a seconda del formato corretto dell'intestazione di sicurezza fornito dal proprietario del servizio che stai utilizzando.

Consuma il metodo (o l'operazione) pertinente:

result=client.service.methodName(Inputs)

Registrazione :

Una delle migliori pratiche in implementazioni come questa è la registrazione per vedere come viene eseguita la comunicazione. In caso di problemi, semplifica il debug. Il codice seguente esegue la registrazione di base. Tuttavia, è possibile registrare molti aspetti della comunicazione oltre a quelli rappresentati nel codice.

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

Risultato:

Ecco il risultato nel mio caso. Notare che il server ha restituito HTTP 200. Questo è il codice di successo standard per la richiesta-risposta 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
      },
 })

1
Potrebbe valere la pena di dire che suds_requestfallirà durante l'installazione, quindi se stai usando suds-jurkofork, puoi installare suds_requestche è stato adattato per funzionare con la versione di suds di jurko:pip install git+https://github.com/chrcoe/suds_requests.git@feature/python3_suds_jurko
errata

7

Al momento (a partire dal 2008), tutte le librerie SOAP disponibili per Python fanno schifo. Consiglio di evitare SOAP se possibile. L'ultima volta che siamo stati costretti a utilizzare un servizio web SOAP di Python, abbiamo scritto un wrapper in C # che gestiva SOAP su un lato e parlava COM sull'altro.


15
Sembra un modo follemente complicato per utilizzare un semplice protocollo basato su xml e http.
ddaa

1
All'epoca, il 2008, questo era il metodo che faceva meno schifo alle nostre esigenze. Mi sembra di ricordare che quel particolare servizio web fosse estremamente schizzinoso su qualcosa che tutte le librerie Python stavano sbagliando.
Matthew Scouten

1
2019, python zeep, suds, ancora soggetto a molti problemi di incompatibilità di analisi. Una cattiva manutenzione dei documenti wsdl farà sì che quei moduli generino eccezioni come petardi non-stop.
mootmoot


6

Cerco periodicamente una risposta soddisfacente a questo, ma finora non ho avuto fortuna. Uso soapUI + richieste + lavoro manuale.

Ho rinunciato e ho usato Java l'ultima volta che avevo bisogno di farlo, e ho rinunciato un paio di volte l'ultima volta che volevo farlo, ma non era essenziale.

Avendo utilizzato con successo la libreria delle richieste l'anno scorso con l'API RESTful di Project Place, mi è venuto in mente che forse avrei potuto semplicemente eseguire il rollio delle richieste SOAP che desidero inviare in modo simile.

Scopre che non è troppo difficile, ma è in termini di tempo e soggetta a errori, soprattutto se i campi sono incoerente di nome (quello che sto attualmente lavorando su oggi ha 'jobId', JobId' e 'JobID'. Io uso soapUI a carico WSDL per semplificare l'estrazione degli endpoint, ecc. ed eseguire alcuni test manuali Finora sono stato fortunato a non essere stato influenzato dalle modifiche a qualsiasi WSDL che sto utilizzando.


3

Non è vero SOAPpy non funziona con Python 2.5 - funziona, anche se è molto semplice e davvero molto semplice. Se vuoi parlare con qualsiasi servizio web più complicato, ZSI è il tuo unico amico.

La demo davvero utile che ho trovato è su http://www.ebi.ac.uk/Tools/webservices/tutorials/python - questo mi ha davvero aiutato a capire come funziona ZSI.


1
L'installazione di python setup.py restituisce errori con l'ultima versione. L'ultima copia dev potrebbe funzionare, ma è una seccatura da fare.
davidmytton


1

SOAPpy è ora obsoleto, AFAIK, sostituito da ZSL. È un punto controverso, perché non riesco a far funzionare nessuno dei due, tanto meno la compilazione, su Python 2.5 o Python 2.6


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']))


output di esempio: ... DEBUG: pysimplesoap.helpers: complexContent / simpleType / element string = string [u'StockQuote '] GetQuote: <StockQuotes><Stock><Symbol>GOOG</Symbol> <Last> 816.13 </Last> <Data> 2017/3/23 </ Date> <Time> 11:41 </ Ora> <Cambia> -13,46 </ Modifica> <Apri> 820,01 </ Open> <High> 822,57 </ alto> <basso> 812,26 </Low> <Volume> 1973140 </Volume> <MktCap> 564.29B </MktCap> <PreviousClose> 829,59 </PreviousClose> <PercentageChange> -1,62% </PercentageChange> <AnnRange> 663,28 - 853,50 </AnnRange> <Earns>27.88</Earns><PE>29.28</PE> <Name> Alphabet Inc. </Name> </Stock> </StockQuotes>
Down the Stream

fallisce su Python3 in pysimplesoap / client.py: 757 - l'oggetto 'dict' non ha attributo 'iteritems'
ierdna

a quanto pare la versione fornita con PIP è rotta. devo installarlo manualmente da GIT - risolve le cose
ierdna

Buon punto: vedi questo link: stackoverflow.com/questions/13998492/iteritems-in-python "dict.iteritems è stato rimosso perché dict.items ora fa il dict.iteritems cosa hanno fatto in Python 2 ..."
lungo il torrente
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.