ChatGPT解决这个技术问题 Extra ChatGPT

How can I consume a WSDL (SOAP) web service in Python?

I want to use a WSDL SOAP based web service in Python. I have looked at the Dive Into Python code but the SOAPpy module does not work under Python 2.5.

I have tried using suds which works partly, but breaks with certain types (suds.TypeNotFound: Type not found: 'item').

I have also looked at Client but this does not appear to support WSDL.

And I have looked at ZSI but it looks very complex. Does anyone have any sample code for it?

The WSDL is https://ws.pingdom.com/soap/PingdomAPI.wsdl and works fine with the PHP 5 SOAP client.

Would you consider changing your accepted answer? The currently accepted answer is -1, and there's another answer with +19. I know this is from 2008; I'm just suggesting.
SUDS didn't work as it couldn't parse the WSDL properly but would be a good choice otherwise. So I changed the answer to a tutorial from Dive Into Python which has some alternatives. As a side note, Pingdom now has a REST API pingdom.com/services/api-documentation-rest with client libraries at blog.pingdom.com/2011/04/11/pingdom-rest-api-wrappers

Y
Yusufk

I would recommend that you have a look at SUDS

"Suds is a lightweight SOAP python client for consuming Web Services."


Seconded. Suds made immediate sense to me, no class generation, it loads the WSDL live and creates an object you can immediately use from it.
Suds has an infinite recursion problem when opening WSDL with recursive imports. This is considered a blocking bug by Suds, and the issue was created over 3 years ago, but it hasn't been fixed yet. fedorahosted.org/suds/ticket/239 It makes me wonder if Suds is suitable for use in 2012?
suds seems dead. Long live SUDS - this seems to be the active Fork.
This is the top answer, but if anyone's looking for an answer that works today, consider Zeep, as the newer answers suggest, too.
C
Community

There is a relatively new library which is very promising and albeit still poorly documented, seems very clean and pythonic: python zeep.

See also this answer for an example.


+1 for this. I tried zeep today and it was surprisingly easy to use. Was able to consume and call a Soap 1.1/1.2 service with 3 lines of code.
But zeep doesn't support raw XML request
T
Teddy Belay

I recently stumbled up on the same problem. Here is the synopsis of my solution:

Basic constituent code blocks needed

The following are the required basic code blocks of your client application

Session request section: request a session with the provider Session authentication section: provide credentials to the provider Client section: create the Client Security Header section: add the WS-Security Header to the Client Consumption section: consume available operations (or methods) as needed

What modules do you need?

Many suggested to use Python modules such as urllib2 ; however, none of the modules work-at least for this particular project.

So, here is the list of the modules you need to get. First of all, you need to download and install the latest version of suds from the following link:

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

Additionally, you need to download and install requests and suds_requests modules from the following links respectively ( disclaimer: I am new to post in here, so I can't post more than one link for now).

pypi.python.org/pypi/requests pypi.python.org/pypi/suds_requests/0.1

Once you successfully download and install these modules, you are good to go.

The code

Following the steps outlined earlier, the code looks like the following: 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

Session request and authentication:

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

Create the Client:

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

Add WS-Security Header:

...
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)

Please note that this method creates the security header depicted in Fig.1. So, your implementation may vary depending on the correct security header format provided by the owner of the service you are consuming.

Consume the relevant method (or operation) :

result=client.service.methodName(Inputs)

Logging:

One of the best practices in such implementations as this one is logging to see how the communication is executed. In case there is some issue, it makes debugging easy. The following code does basic logging. However, you can log many aspects of the communication in addition to the ones depicted in the code.

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

Result:

Here is the result in my case. Note that the server returned HTTP 200. This is the standard success code for HTTP request-response.

(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
      },
 })

Might be worth of saying that suds_request will fail while installing, so if you are using suds-jurko fork, you can install suds_request which was adapted to work with jurko's version of suds: pip install git+https://github.com/chrcoe/suds_requests.git@feature/python3_suds_jurko
A
Al Sweigart

Zeep is a decent SOAP library for Python that matches what you're asking for: http://docs.python-zeep.org


Duplicate answer (please close this one and upvote stackoverflow.com/a/36910649/948581)
t
the Tin Man

Right now (as of 2008), all the SOAP libraries available for Python suck. I recommend avoiding SOAP if possible. The last time we where forced to use a SOAP web service from Python, we wrote a wrapper in C# that handled the SOAP on one side and spoke COM out the other.


That sounds like an insanely complicated way to use a simple protocol based on xml and http.
At the time, 2008, this was the method that sucked the least for our needs. I seem to remember that that particular web service was extremely picky about something that all the python libraries were getting wrong.
2019, python zeep, suds, still prone to many parsing incompatibility issues. Poorly maintain wsdl documents will make those modules throw exception like non-stop firecracker.
H
Hywel Thomas

I periodically search for a satisfactory answer to this, but no luck so far. I use soapUI + requests + manual labour.

I gave up and used Java the last time I needed to do this, and simply gave up a few times the last time I wanted to do this, but it wasn't essential.

Having successfully used the requests library last year with Project Place's RESTful API, it occurred to me that maybe I could just hand-roll the SOAP requests I want to send in a similar way.

Turns out that's not too difficult, but it is time consuming and prone to error, especially if fields are inconsistently named (the one I'm currently working on today has 'jobId', JobId' and 'JobID'. I use soapUI to load the WSDL to make it easier to extract endpoints etc and perform some manual testing. So far I've been lucky not to have been affected by changes to any WSDL that I'm using.


z
zgoda

It's not true SOAPpy does not work with Python 2.5 - it works, although it's very simple and really, really basic. If you want to talk to any more complicated webservice, ZSI is your only friend.

The really useful demo I found is at http://www.ebi.ac.uk/Tools/webservices/tutorials/python - this really helped me to understand how ZSI works.


python setup.py install gives errors with the latest release. The latest dev copy might work but that's a pain to do.
s
sj26

If you're rolling your own I'd highly recommend looking at http://effbot.org/zone/element-soap.htm.


t
the Tin Man

SOAPpy is now obsolete, AFAIK, replaced by ZSL. It's a moot point, because I can't get either one to work, much less compile, on either Python 2.5 or Python 2.6


D
Down the Stream
#!/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']))

the lib is listed here: code.google.com/archive/p/pysimplesoap
sample output: ... DEBUG:pysimplesoap.helpers:complexContent/simpleType/element string = string [u'StockQuote'] GetQuote: GOOG816.133/23/2017-13.46820.01822.57812.261973140564.29B829.59-1.62%663.28 - 853.5027.8829.28Alphabet Inc.
fails on Python3 in pysimplesoap/client.py:757 -- 'dict' object has no attribute 'iteritems'
apparently version that comes with PIP is broken. have to install it manually from GIT - it fixes things
Good point: see this link:stackoverflow.com/questions/13998492/iteritems-in-python "dict.iteritems was removed because dict.items now does the thing dict.iteritems did in python 2..."