如何在Python中使用WSDL(SOAP)Web服务?

问题:如何在Python中使用WSDL(SOAP)Web服务?

我想在Python中使用基于WSDL SOAP的Web服务。我看过Dive Into Python代码,但是SOAPpy模块在Python 2.5下不起作用。

我已经尝试使用肥皂水(:类型未找到:“项目” suds.TypeNotFound),这部分工作,但打破了某些类型。

我也查看了Client,但这似乎不支持WSDL。

我看过ZSI,但它看起来非常复杂。有人有任何示例代码吗?

WSDL是https://ws.pingdom.com/soap/PingdomAPI.wsdl,可与PHP 5 SOAP客户端配合使用。

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.


回答 0

我建议您看看SUDS

“ Suds是用于使用Web服务的轻量级SOAP python客户端。”

I would recommend that you have a look at SUDS

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


回答 1

有一个相对较新的库,它很有前途,尽管文档仍然很少,但看起来很干净并且是pythonic的python zeep

另请参见此答案的示例。

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.


回答 2

我最近偶然发现了同样的问题。这是我的解决方案的摘要:

所需的基本组成代码块

以下是客户端应用程序所需的基本代码块

  1. 会话请求部分:请求与提供者进行会话
  2. 会话认证部分:向提供者提供凭据
  3. 客户端部分:创建客户端
  4. 安全标题部分:将WS-Security标头添加到客户端
  5. 消耗部分:根据需要消耗可用的操作(或方法)

您需要什么模块?

许多建议使用Python模块,例如urllib2;但是,这些模块都不起作用-至少对于该特定项目不起作用。

因此,这是您需要获取的模块列表。首先,您需要从以下链接下载并安装最新版本的suds:

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

此外,您需要分别从以下链接下载和安装请求和suds_requests模块(免责声明:我是新来此发布者,因此我现在不能发布多个链接)。

pypi.python.org/pypi/requests

pypi.python.org/pypi/suds_requests/0.1

一旦成功下载并安装了这些模块,就可以了。

代码

按照前面概述的步骤,代码如下所示:导入:

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

会话请求和身份验证:

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

添加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)

请注意,此方法将创建图1所示的安全标头。因此,您的实现可能会有所不同,具体取决于所使用服务的所有者提供的正确安全标头格式。

消耗相关的方法(或操作):

result=client.service.methodName(Inputs)

正在记录

在这种实现中的最佳实践之一是记录日志,以查看通信是如何执行的。万一有问题,它使调试变得容易。以下代码进行基本日志记录。但是,除了代码中描述的内容外,您还可以记录通信的许多方面。

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

结果:

这是我的情况的结果。请注意,服务器返回了HTTP200。这是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
      },
 })

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

  1. Session request section: request a session with the provider
  2. Session authentication section: provide credentials to the provider
  3. Client section: create the Client
  4. Security Header section: add the WS-Security Header to the Client
  5. 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
      },
 })

回答 3

现在(截止到2008年),所有可用于Python的SOAP库都非常烂。我建议尽可能避免使用SOAP。上次我们被迫使用Python中的SOAP Web服务时,我们用C#编写了一个包装器,该包装器一方面处理SOAP,另一方面则使COM退出。

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.


回答 4

Zeep是一个适合Python的不错的SOAP库,它可以满足您的要求:http : //docs.python-zeep.org

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


回答 5

我定期寻找一个令人满意的答案,但是到目前为止还没有运气。我使用soapUI +请求+体力劳动。

我上次要这样做时放弃并使用了Java ,而上次我这样做时仅放弃了几次,但这并不是必需的。

去年在Project Place的RESTful API中成功使用了请求库之后,我想到也许我可以以类似的方式手动滚动要发送的SOAP请求。

事实证明,这并不是很困难,但是这耗时且容易出错,尤其是如果字段名称不一致(我当前正在使用的字段具有“ jobId”,“ JobId”和“ JobID”。我使用soapUI加载) WSDL,以便更轻松地提取端点等并执行一些手动测试。到目前为止,我很幸运没有受到我正在使用的任何WSDL更改的影响。

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.


回答 6

并非如此,SOAPpy不适用于Python 2.5-它可以工作,尽管它非常简单,而且确实非常基础。如果您想与任何更复杂的Web服务进行对话,则ZSI是您唯一的朋友。

我发现的真正有用的演示位于http://www.ebi.ac.uk/Tools/webservices/tutorials/python-这确实帮助我了解了ZSI的工作原理。

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.


回答 7

如果您要自己动手,则强烈建议您访问http://effbot.org/zone/element-soap.htm

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


回答 8

SOAPpy现在已过时,已经被ZSL取代了AFAIK。这是有争议的,因为在Python 2.5或Python 2.6上我都无法工作,更不用说编译了。

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


回答 9

#!/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']))
#!/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']))