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
10 Answers 10
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?
This is the top answer, but if anyone’s looking for an answer that works today, consider Zeep, as the newer answers suggest, too.
There is a relatively new library which is very promising and albeit still poorly documented, seems very clean and pythonic: python zeep.
+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.
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:
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).
Once you successfully download and install these modules, you are good to go.
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)
client = Client(WSDL_URL, faults=False, cachingpolicy=1, location=WSDL_URL, transport=suds_requests.RequestsTransport(session))
. 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)
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)
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 >, >)
SOAP и REST сервисы с помощью Python-библиотеки Spyne
В данной статье я хочу рассказать о замечательной Python-библиотеке Spyne. Мое знакомство с Spyne началось в тот момент, когда передо мной поставили задачу написать Веб-сервис, который будет принимать и отдавать запросы через SOAP-протокол. Немного погуглив я наткнулся на Spyne, которая является форком библиотеки soaplib. А еще я был удивлен, насколько мало русскоязычной информации встречается о данной библиотеке.
С помощью Spyne можно писать веб-сервисы, которые умеют работать с SOAP, JSON, YAML, а написанный скрипт можно запустить через mod_wsgi Apache. Итак, давайте рассмотрим несколько примеров, напишем работающие скрипты и настроим так, чтобы скрипты работали через apache.
1. SOAP-сервис
Давайте напишем веб-сервис, который будет служить нам переводчиком на английский язык. Наш веб-сервис будет получать запросы, обращаться в Yandex-translator, получать перевод и данный перевод отдавать клиенту. Принимаются входящие запросы в XML-формате. Ответ также будет уходить в XML-формате.
Первым делом необходимо получить API-ключ, чтобы сказать Яндексу, что мы свои. Как можно это сделать, смотрим тут.
Теперь переходим непосредственно к разработке.
Устанавливаем необходимые библиотеки: «pytz», «spyne», а также «yandex_translate». Библиотеки ставятся очень легко через pip.
Код приложения выглядит следующим образом:
from spyne import Application, rpc, ServiceBase, Unicode from lxml import etree from spyne.protocol.soap import Soap11 from spyne.protocol.json import JsonDocument from spyne.server.wsgi import WsgiApplication from yandex_translate import YandexTranslate class Soap(ServiceBase): @rpc(Unicode, _returns=Unicode) def Insoap(ctx, words): print(etree.tostring(ctx.in_document)) translate = YandexTranslate('trnsl.1.1.201somesymbols') tr = translate.translate(words, 'en') tr_answer = tr['text'][0] return tr_answer app = Application([Soap], tns='Translator', in_protocol=Soap11(validator='lxml'), out_protocol=Soap11() application = WsgiApplication(app) if __name__ == '__main__': from wsgiref.simple_server import make_server server = make_server('0.0.0.0', 8000, application) server.serve_forever()
После импортирования необходимых библиотек, мы создали класс «Soap» с аргументом «ServiceBase». Декоратор «@rpc(Unicode, _returns=Unicode)» определяет тип входящих аргументов («Unicode») и исходящих ответов («_returns=Unicode»). Список доступных типов аргументов можно посмотреть в официальной документации.. Далее создается метод «Insoap» с аргументами «ctx» и «words». Аргумент «ctx» очень важен, так как в нем содержится много информации о входящих запросах. Строка «print(etree.tostring(ctx.in_document))» выводит на экран входящий xml-запрос, в таком виде, в каком нам его отправил пользователь. В некоторых моментах это может быть важно.
Например, мне в ходе написания веб-сервиса нужно было вытащить входящий xml-запрос и записать в базу данных. Но как вытащить этот xml-запрос не упомянуто в официальной документации Spyne. Burak Arslan (автор Spyne) порекомендовал смотреть в сторону библиотеки lxml. Только после этого я нашел ответ и результат видите в данноме скрипте. Далее наш метод обращается в Яндекс-переводчик и возвращает клиенту полученный от Яндекс-переводчика результат.
Переменная «app» определяет настройки нашего веб-сервиса: «Application([Soap]» — указывается, какой класс инициализируется (их может быть несколько), параметры «in_protocol» и «out_protocol» определяет тип входящих и исходящих запросов, в нашем случае это SOAP v1.1.
Строкой «application = WsgiApplication(app)» определяется, чтобы наш скрипт мог работать через wsgi.
Важно! имя переменного обязательно должен быть «application», чтобы наше приложение мог работать через apache с помощью mod_wsgi. Последующие строки кода инициализирует и запускает Веб-сервер по порту 8000.
Запускаем скрипт и можно приступать к тестированию. Для этих целей я использую SoapUI. Удобство состоит в том, что после запуска и настройки для работы с SOAP сервером, SoapUI автоматически формирует xml-запрос. Настроимся на URL: localhost:8000?wsdl (при условии, что скрипт запущен на локальной машине), и наш xml-запрос выглядит следующим образом:
Наш веб-сервис дал следующий ответ:
2. REST-сервис
Предположим, что теперь у нас поменялось тех. задание, и нужно сделать веб-сервис, который работает через JSON. Что делать? Переписывать наш сервис на другом фреймворке, например Django Rest Framework или Flask? или можно обойтись меньшими усилиями? Да, можно! И нужно!
Библиотека Spyne нам в помошь.
Все что потребуется поменять в нашем приложении, это переменную «app» привести к следующему виду:
app = Application([Soap], tns='Translator', in_protocol=JsonDocument(validator='soft'), out_protocol=JsonDocument())
Запускаем наш веб-сервис и тестируемся.
Наш JSON-запрос выглядит так:
Веб сервер вернул следующий ответ:
3. Вывод в продакшн
Для запуска нашего веб-сервиса через apache, необходимо на сервер установить и настроить веб-сервер apache и mod_wsgi. Данные работы несложно выполнить, опираясь на документацию. Кроме этого, в нашем скрипте мы должны удалить следующие строки:
if __name__ == '__main__': from wsgiref.simple_server import make_server server = make_server('0.0.0.0', 8000, application) server.serve_forever()
Ура! Наш веб-сервис готов к использованию в эксплуатации.
P.S. о дополнительных возможностях Spyne (а их немало) всегда можно ознакомиться на официальном сайте, чего я вам очень рекомендую.
How to Call Soap API with Python
While I’ve used APIs in the past, this is the first SOAP I’ve attempted to use. I copy, pasted, and changed around some of this code from a SOAP tutorial, but I’ve seen it done 10 different ways in 10 different examples, yet none are very clear in explaining the code. Maybe the following code isn’t the best way to do it, but that’s why I’m looking for some help and a clear direction to go in. Thanks so much.
import string, os, sys, httplib server_addr = "auctions.godaddy.com" service_action = "GdAuctionsBiddingWSAPI/GetAuctionList" body = """ """ request = httplib.HTTPConnection(server_addr) request.putrequest("POST", service_action) request.putheader("Accept", "application/soap+xml, application/dime, multipart/related, text/*") request.putheader("Content-Type", "text/xml; charset=utf-8") request.putheader("Cache-Control", "no-cache") request.putheader("Pragma", "no-cache") request.putheader("SOAPAction", "https://auctions.godaddy.com/gdAuctionsWSAPI/gdAuctionsBiddingWS.asmx?op=GetAuctionList" + server_addr + service_action) request.putheader("Content-Length", "length") request.putheader("apiKey", "xxxxxx") request.putheader("pageNumber", "1") request.putheader("rowsPerPage", "1") request.putheader("beginsWithKeyword", "word") request.endheaders() request.send(body) response = request.getresponse().read() print response