ChatGPT解决这个技术问题 Extra ChatGPT

Sending SOAP request using Python Requests

Is it possible to use Python's requests library to send a SOAP request?

not supposed to use suds ;
@DeepankarBajpeyi why not? It's the only tool suitable for the job.
You can pass a requests.Session to zeep.
@IanStapletonCordasco even in 2013 suds was dead.

t
toast38coza

It is indeed possible.

Here is an example calling the Weather SOAP Service using plain requests lib:

import requests
url="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"
#headers = {'content-type': 'application/soap+xml'}
headers = {'content-type': 'text/xml'}
body = """<?xml version="1.0" encoding="UTF-8"?>
         <SOAP-ENV:Envelope xmlns:ns0="http://ws.cdyne.com/WeatherWS/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
            <SOAP-ENV:Header/>
              <ns1:Body><ns0:GetWeatherInformation/></ns1:Body>
         </SOAP-ENV:Envelope>"""

response = requests.post(url,data=body,headers=headers)
print response.content

Some notes:

The headers are important. Most SOAP requests will not work without the correct headers. application/soap+xml is probably the more correct header to use (but the weatherservice prefers text/xml

This will return the response as a string of xml - you would then need to parse that xml.

For simplicity I have included the request as plain text. But best practise would be to store this as a template, then you can load it using jinja2 (for example) - and also pass in variables.

For example:

from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('myapp', 'templates'))
template = env.get_template('soaprequests/WeatherSericeRequest.xml')
body = template.render()

Some people have mentioned the suds library. Suds is probably the more correct way to be interacting with SOAP, but I often find that it panics a little when you have WDSLs that are badly formed (which, TBH, is more likely than not when you're dealing with an institution that still uses SOAP ;) ).

You can do the above with suds like so:

from suds.client import Client
url="http://wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL"
client = Client(url)
print client ## shows the details of this service

result = client.service.GetWeatherInformation() 
print result 

Note: when using suds, you will almost always end up needing to use the doctor!

Finally, a little bonus for debugging SOAP; TCPdump is your friend. On Mac, you can run TCPdump like so:

sudo tcpdump -As 0 

This can be helpful for inspecting the requests that actually go over the wire.

The above two code snippets are also available as gists:

SOAP Request with requests

SOAP Request with suds


what if the service requests username and password? where to note them?
@toast38coza wsf.cdyne.com/WeatherWS/Weather.asmx?WSDL --> Server Error in '/WeatherWS' Application. Please update the example.
@toast38coza Where do I get information for headers and body variables in the requests example above?
The Suds documentation is no longer available on fedorahosted.org. Here's a link to a snapshot of the documentation on the Wayback Machine.
Whatever "use the doctor" is supposed to mean, that link is now dead.
J
Jesus Perez

Adding up to the last answer, make sure you add to the headers the following attributes:

headers={"Authorization": f"bearer {token}", "SOAPAction": "http://..."}

The authorization is meant when you need some token to access the SOAP API,

Otherwise, the SOAPAction is the action you are going to perform with the data you are sending in,

So if you don't need Authorization, then you could pop that out of the headers,

That worked pretty fine for me,