¿Cómo puedo consumir un servicio web WSDL (SOAP) en Python?

124

Quiero usar un servicio web basado en SOAP WSDL en Python. He mirado el código Dive Into Python pero el módulo SOAPpy no funciona en Python 2.5.

He intentado usar suds que funciona en parte, pero rompe con ciertos tipos (suds.TypeNotFound: Type not found: 'item').

También he mirado al Cliente, pero esto no parece admitir WSDL.

Y he mirado a ZSI pero parece muy complejo. ¿Alguien tiene algún código de muestra?

El WSDL es https://ws.pingdom.com/soap/PingdomAPI.wsdl y funciona bien con el cliente PHP 5 SOAP.

davidmytton
fuente
3
¿Consideraría cambiar su respuesta aceptada? La respuesta actualmente aceptada es -1, y hay otra respuesta con +19. Sé que esto es de 2008; Solo estoy sugiriendo.
Mark E. Haase
SUDS no funcionó ya que no podría analizar el WSDL correctamente, pero de lo contrario sería una buena opción. Así que cambié la respuesta a un tutorial de Dive Into Python que tiene algunas alternativas. Como nota al margen, Pingdom ahora tiene una API REST pingdom.com/services/api-documentation-rest con bibliotecas de clientes en blog.pingdom.com/2011/04/11/pingdom-rest-api-wrappers
davidmytton

Respuestas:

49

Te recomendaría que eches un vistazo a SUDS

"Suds es un cliente ligero de python SOAP para consumir servicios web".

Yusufk
fuente
Secundado Suds tenía sentido inmediato para mí, sin generación de clase, carga el WSDL en vivo y crea un objeto que puede usar inmediatamente.
EnigmaCurry
19
Suds tiene un problema de recursión infinito al abrir WSDL con importaciones recursivas. Suds lo considera un error de bloqueo, y el problema se creó hace más de 3 años, pero aún no se ha solucionado. fedorahosted.org/suds/ticket/239 ¿ Me hace preguntarme si Suds es adecuado para usar en 2012?
Botones840
2
La espuma parece muerta. Larga vida a SUDS : esta parece ser la bifurcación activa.
nerdoc
3
Esta es la respuesta principal, pero si alguien está buscando una respuesta que funcione hoy, considere Zeep , como sugieren las respuestas más recientes.
Tobias Feil
25

Hay una biblioteca relativamente nueva que es muy prometedora y, aunque todavía está mal documentada, parece muy limpia y pitónica: python zeep .

Vea también esta respuesta para un ejemplo.

lorenzog
fuente
2
+1 por esto. Intenté zeep hoy y fue sorprendentemente fácil de usar. Pude consumir y llamar a un servicio Soap 1.1 / 1.2 con 3 líneas de código.
Jagu
20

Recientemente me topé con el mismo problema. Aquí está la sinopsis de mi solución:

Se necesitan bloques de código constituyente básicos

Los siguientes son los bloques de código básicos necesarios de su aplicación cliente

  1. Sección de solicitud de sesión: solicite una sesión con el proveedor
  2. Sección de autenticación de sesión: proporcionar credenciales al proveedor
  3. Sección del cliente: crear el cliente
  4. Sección del encabezado de seguridad: agregue el encabezado WS-Security al cliente
  5. Sección de consumo: consuma las operaciones disponibles (o métodos) según sea necesario

¿Qué módulos necesitas?

Muchos sugirieron usar módulos de Python como urllib2; sin embargo, ninguno de los módulos funciona, al menos para este proyecto en particular.

Entonces, aquí está la lista de los módulos que necesita obtener. En primer lugar, debe descargar e instalar la última versión de espuma desde el siguiente enlace:

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

Además, debe descargar e instalar solicitudes y módulos de suds_requests desde los siguientes enlaces respectivamente (descargo de responsabilidad: soy nuevo para publicar aquí, por lo que no puedo publicar más de un enlace por ahora).

pypi.python.org/pypi/requests

pypi.python.org/pypi/suds_requests/0.1

Una vez que descargue e instale con éxito estos módulos, está listo para comenzar.

El código

Siguiendo los pasos descritos anteriormente, el código tiene el siguiente aspecto: Importaciones:

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

Solicitud de sesión y autenticación:

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

Crea el cliente:

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

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

Tenga en cuenta que este método crea el encabezado de seguridad representado en la Fig.1. Por lo tanto, su implementación puede variar según el formato de encabezado de seguridad correcto proporcionado por el propietario del servicio que está consumiendo.

Consuma el método (u operación) relevante:

result=client.service.methodName(Inputs)

Registro :

Una de las mejores prácticas en implementaciones como esta es iniciar sesión para ver cómo se ejecuta la comunicación. En caso de que haya algún problema, facilita la depuración. El siguiente código hace un registro básico. Sin embargo, puede registrar muchos aspectos de la comunicación además de los que se muestran en el código.

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

Resultado:

Aquí está el resultado en mi caso. Tenga en cuenta que el servidor devolvió HTTP 200. Este es el código de éxito estándar para la solicitud-respuesta 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
fuente
1
Podría valer la pena decir que suds_requestfallará durante la instalación, por lo que si está utilizando suds-jurkofork, puede instalar el suds_requestque fue adaptado para funcionar con la versión de espuma de jurko:pip install git+https://github.com/chrcoe/suds_requests.git@feature/python3_suds_jurko
errata
7

En este momento (a partir de 2008), todas las bibliotecas SOAP disponibles para Python apestan. Recomiendo evitar SOAP si es posible. La última vez que nos vimos obligados a usar un servicio web SOAP de Python, escribimos un contenedor en C # que manejaba el SOAP por un lado y hablaba COM por el otro.

Matthew Scouten
fuente
15
Eso suena como una forma increíblemente complicada de usar un protocolo simple basado en xml y http.
ddaa
1
En ese momento, 2008, este era el método que menos apestaba a nuestras necesidades. Me parece recordar que ese servicio web en particular era extremadamente exigente con algo en lo que todas las bibliotecas de Python se estaban equivocando.
Matthew Scouten
1
2019, python zeep, espuma, aún propenso a muchos problemas de incompatibilidad de análisis. El mantenimiento deficiente de los documentos wsdl hará que esos módulos arrojen excepciones como petardos sin parar.
mootmoot
6

Periódicamente busco una respuesta satisfactoria a esto, pero hasta ahora no he tenido suerte. Yo uso soapUI + solicitudes + trabajo manual.

Me di por vencido y usé Java la última vez que necesitaba hacer esto, y simplemente me rendí varias veces la última vez que quise hacerlo, pero no fue esencial.

Habiendo utilizado con éxito la biblioteca de solicitudes el año pasado con la API RESTful de Project Place, se me ocurrió que tal vez podría simplemente transferir manualmente las solicitudes SOAP que quiero enviar de una manera similar.

Resulta que no es demasiado difícil, pero lleva mucho tiempo y es propenso a errores, especialmente si los campos tienen un nombre inconsistente (en el que estoy trabajando actualmente tiene 'jobId', JobId 'y' JobID '. Utilizo soapUI para cargar WSDL para facilitar la extracción de puntos finales, etc. y realizar algunas pruebas manuales. Hasta ahora he tenido la suerte de no haber sido afectado por los cambios en cualquier WSDL que estoy usando.

Hywel Thomas
fuente
3

No es cierto SOAPpy no funciona con Python 2.5, funciona, aunque es muy simple y muy, muy básico. Si desea hablar con un servicio web más complicado, ZSI es su único amigo.

La demostración realmente útil que encontré está en http://www.ebi.ac.uk/Tools/webservices/tutorials/python ; esto realmente me ayudó a comprender cómo funciona ZSI.

zgoda
fuente
1
La instalación de python setup.py produce errores con la última versión. La última copia de desarrollo podría funcionar, pero eso es difícil de hacer.
davidmytton
1

SOAPpy ahora está obsoleto, AFAIK, reemplazado por ZSL. Es un punto discutible, porque no puedo hacer que ninguno funcione, mucho menos compilar, en Python 2.5 o Python 2.6

el hombre de hojalata
fuente
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']))
Por la corriente
fuente
la lib aparece aquí: code.google.com/archive/p/pysimplesoap
Down the Stream el
salida de muestra: ... DEPURACIÓN: pysimplesoap.helpers: complexContent / simpleType / element string = string [u'StockQuote '] GetQuote: <StockQuotes><Stock><Symbol>GOOG</Symbol> <Last> 816.13 </Last> <Fecha> 23/03/2017</Fecha><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 </> <Earns>27.88</Earns><PE>29.28</PE> <Name> Alphabet Inc. </Name> </Stock> </StockQuotes>
Down the Stream
falla en Python3 en pysimplesoap / client.py: 757 - el objeto 'dict' no tiene ningún atributo 'iteritems'
ierdna
aparentemente la versión que viene con PIP está rota. tiene que instalarlo manualmente desde GIT - soluciona las cosas
ierdna
Buen punto: vea este enlace: stackoverflow.com/questions/13998492/iteritems-in-python "dict.iteritems fue eliminado porque dict.items ahora hace lo que dict.iteritems hizo en python 2 ..."
Down the Stream