Como posso consumir um serviço da Web WSDL (SOAP) em Python?

124

Desejo usar um serviço da Web baseado em WSDL SOAP em Python. Eu observei o código Dive Into Python , mas o módulo SOAPpy não funciona no Python 2.5.

Eu tentei usar o suds, que funciona parcialmente, mas quebra com certos tipos (suds.TypeNotFound: Type not found: 'item').

Eu também olhei para o cliente, mas isso não parece oferecer suporte ao WSDL.

E eu olhei para o ZSI, mas parece muito complexo. Alguém tem algum código de exemplo para isso?

O WSDL é https://ws.pingdom.com/soap/PingdomAPI.wsdl e funciona bem com o cliente SOAP do PHP 5.

davidmytton
fonte
3
Você consideraria alterar sua resposta aceita? A resposta atualmente aceita é -1, e há outra resposta com +19. Eu sei que isso é de 2008; Estou apenas sugerindo.
Mark E. Haase
O SUDS não funcionou, pois não poderia analisar o WSDL corretamente, mas seria uma boa opção caso contrário. Então mudei a resposta para um tutorial do Dive Into Python, que tem algumas alternativas. Como observação lateral, o Pingdom agora possui uma API REST pingdom.com/services/api-documentation-rest com bibliotecas de clientes em blog.pingdom.com/2011/04/11/pingdom-rest-api-wrappers
davidmytton

Respostas:

49

Eu recomendaria que você desse uma olhada no SUDS

"O Suds é um cliente python SOAP leve para consumir serviços da Web."

Yusufk
fonte
Destacado. Suds fez sentido imediatamente para mim, sem geração de classe, ele carrega o WSDL live e cria um objeto que você pode usar imediatamente.
EnigmaCurry 23/02
19
O Suds tem um problema de recursão infinito ao abrir o WSDL com importações recursivas. Isso é considerado um bug de bloqueio pelo Suds, e o problema foi criado há mais de 3 anos, mas ainda não foi corrigido. fedorahosted.org/suds/ticket/239 Isso me faz pensar se o Suds é adequado para uso em 2012?
Buttons840
2
espuma parece morta. Viva SUDS - este parece ser o Fork ativo.
Nerdoc
3
Essa é a resposta principal, mas se alguém estiver procurando por uma resposta que funcione hoje, considere o Zeep , como sugerem as respostas mais recentes.
Tobias Feil
25

Existe uma biblioteca relativamente nova que é muito promissora e, embora ainda mal documentada, parece muito limpa e pitônica : python zeep .

Veja também esta resposta para um exemplo.

Lorenzog
fonte
2
+1 para isso. Eu tentei zeep hoje e era surpreendentemente fácil de usar. Conseguiu consumir e chamar um serviço Soap 1.1 / 1.2 com 3 linhas de código.
Jagu 10/01
20

Recentemente, me deparei com o mesmo problema. Aqui está a sinopse da minha solução:

Blocos básicos de código constituinte necessários

A seguir, estão os blocos de código básico necessários do seu aplicativo cliente

  1. Seção de solicitação de sessão: solicite uma sessão com o provedor
  2. Seção de autenticação de sessão: forneça credenciais ao provedor
  3. Seção Cliente: crie o Cliente
  4. Seção Cabeçalho de Segurança: adicione o Cabeçalho WS-Security ao Cliente
  5. Seção Consumo: consuma as operações disponíveis (ou métodos) conforme necessário

Quais módulos você precisa?

Muitos sugeriram o uso de módulos Python como o urllib2; no entanto, nenhum dos módulos funciona, pelo menos para este projeto em particular.

Então, aqui está a lista dos módulos que você precisa obter. Primeiro de tudo, você precisa baixar e instalar a versão mais recente do suds no seguinte link:

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

Além disso, você precisa fazer o download e instalar módulos de solicitações e suds_requests a partir dos seguintes links, respectivamente (aviso de isenção de responsabilidade: sou novo em publicar aqui, portanto não posso postar mais de um link no momento).

pypi.python.org/pypi/requests

pypi.python.org/pypi/suds_requests/0.1

Depois de baixar e instalar esses módulos, você estará pronto.

O código

Seguindo as etapas descritas anteriormente, o código é semelhante ao seguinte: Importações:

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

Solicitação e autenticação de sessão:

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

Crie o cliente:

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

Adicione o cabeçalho 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)

Observe que este método cria o cabeçalho de segurança descrito na Fig.1. Portanto, sua implementação pode variar dependendo do formato correto do cabeçalho de segurança fornecido pelo proprietário do serviço que você está consumindo.

Consumir o método (ou operação) relevante:

result=client.service.methodName(Inputs)

Registro :

Uma das melhores práticas em implementações como esta é o log para ver como a comunicação é executada. Caso haja algum problema, isso facilita a depuração. O código a seguir faz o log básico. No entanto, você pode registrar muitos aspectos da comunicação, além dos descritos no código.

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

Resultado:

Aqui está o resultado no meu caso. Observe que o servidor retornou o HTTP 200. Esse é o código de sucesso padrão para a solicitação-resposta 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
      },
 })
Teddy Belay
fonte
1
Talvez valesse a pena de dizer que suds_requestirá falhar durante a instalação, por isso, se você estiver usando suds-jurkoum garfo, você pode instalar suds_requesto qual foi adaptado para trabalhar com a versão de Jurko de espuma:pip install git+https://github.com/chrcoe/suds_requests.git@feature/python3_suds_jurko
errata
7

No momento (a partir de 2008), todas as bibliotecas SOAP disponíveis para o Python são péssimas. Eu recomendo evitar SOAP, se possível. Na última vez em que fomos forçados a usar um serviço Web SOAP do Python, escrevemos um wrapper em C # que tratava o SOAP de um lado e falava COM do outro.

Matthew Scouten
fonte
15
Isso soa como uma maneira incrivelmente complicada de usar um protocolo simples baseado em xml e http.
Ddaa
1
Na época, 2008, esse era o método que menos sugava nossas necessidades. Parece que me lembro que esse serviço da Web em particular era extremamente exigente quanto a algo que todas as bibliotecas python estavam errando.
Matthew Scouten
1
2019, python zeep, suds, ainda propenso a muitos problemas de incompatibilidade de análise. Manter documentos wsdl com pouca qualidade fará com que esses módulos gerem exceções como fogos de artifício ininterruptos.
Mootmoot 10/05/19
6

Eu procuro periodicamente por uma resposta satisfatória para isso, mas sem sorte até agora. Eu uso soapUI + pedidos + trabalho manual.

Desisti e usei o Java da última vez que precisei , e simplesmente desisti algumas vezes da última vez que queria fazer isso, mas não era essencial.

Tendo usado com sucesso a biblioteca de solicitações no ano passado com a API RESTful do Project Place, ocorreu-me que talvez eu pudesse apenas rolar manualmente as solicitações SOAP que desejo enviar de maneira semelhante.

Acontece que isso não é muito difícil, mas é demorado e propenso a erros, especialmente se os campos tiverem um nome inconsistente (o que eu estou trabalhando atualmente hoje tem 'jobId', JobId 'e' JobID '. Eu uso o soapUI para carregar o WSDL para facilitar a extração de pontos de extremidade etc. e realizar alguns testes manuais Até agora, tive a sorte de não ter sido afetado por alterações em nenhum WSDL que estou usando.

Hywel Thomas
fonte
3

Não é verdade que o SOAPpy não funciona com o Python 2.5 - funciona, embora seja muito simples e muito, muito básico. Se você deseja conversar com qualquer serviço da Web mais complicado, o ZSI é seu único amigo.

A demonstração realmente útil que encontrei está em http://www.ebi.ac.uk/Tools/webservices/tutorials/python - isso realmente me ajudou a entender como o ZSI funciona.

zgoda
fonte
1
A instalação do python setup.py apresenta erros na versão mais recente. A cópia mais recente do desenvolvedor pode funcionar, mas é uma tarefa difícil.
davidmytton 22/09/08
1

O SOAPpy agora está obsoleto, AFAIK, substituído por ZSL. É um ponto discutível, porque não consigo que nenhum deles funcione, muito menos compile, no Python 2.5 ou no Python 2.6

o homem de lata
fonte
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']))
Down the Stream
fonte
a lib está listada aqui: code.google.com/archive/p/pysimplesoap
Down the Stream
saída de amostra: ... DEBUG: pysimplesoap.helpers: complexContent / simpleType / elemento string = string [u'StockQuote '] GetQuote: <StockQuotes><Stock><Symbol>GOOG</Symbol> <Last> 816.13 </Last> <Data>3/23/2017</Data><Time> 11:41am</Time><Change>-13.46</Change><Open>820.01</Open><High>822.57</High> <Low> 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
falha em Python3 em pysimplesoap / client.py: 757 - objeto 'dict' tem nenhum atributo 'iteritems'
ierdna
aparentemente a versão que vem com o PIP está quebrada. tem que instalá-lo manualmente a partir do GIT - ele corrige as coisas
ierdna
Bom ponto: veja este link: stackoverflow.com/questions/13998492/iteritems-in-python "dict.iteritems foi removido porque dict.items agora faz o que dict.iteritems fez no python 2 ..."
Down the Stream