\ お問い合わせはこちら! /

Python で SOAP リクエストを送ってレスポンスを調べる方法

  • SOAP にアクセスする必要があるのだけど、どうしたらいいかわからない!

このような疑問にお答えします。

最近の API サーバーは REST がほとんどなので、SOAP と言われると面食らってしまいます。

とはいえ Python では SOAP を簡単に扱えるzeepというライブラリがあるので、基本的にはこれを使えば大丈夫です。

とはいえzeepライブラリが使えないシチュエーションもあると思うので、代替手段としてrequestsライブラリを使った実装方法もご紹介します。

zeep ライブラリを使う方法

Python では SOAP クライアントのzeepライブラリを使う方法が一般的です。

順を追って、使い方を解説していきます。

インストール

まずはzeepをインストールしましょう。

pip install zeep

インストールが正常にできているか、以下のコマンドで確認してみましょう。

pip list | grep zeep

以下のように返ってくれば成功です。

zeep  4.2.1

基本的な使用方法

早速zeepで SOAP リクエストを送信しましょう。

from zeep import Client

# WSDL(Web Services Description Language)のURLを指定
wsdl = "https://www.example.com/service?wsdl"

# クライアントを作成
client = Client(wsdl=wsdl)

# サービスを呼び出し
response = client.service.YourOperation(YourParameter="value")

# レスポンスを表示
if response["Status"] == "Success":
    print("Weather:", response["Weather"])
    print("Temperature:", response["Temperature"])
else:
    print("Error:", response["Status"])

エラーハンドリング

リクエスト時にエラーとなってしまうことに備え、エラーハンドリングをした例です。

from zeep import Client
from zeep.exceptions import Fault

# WSDLのURL
wsdl = "http://www.webservicex.net/globalweather.asmx?WSDL"

# クライアントを作成
client = Client(wsdl=wsdl)

try:
    # サービスを呼び出し
    response = client.service.GetWeather(CityName="Tokyo", CountryName="Japan")
    print(response)
except Fault as fault:
    print(f"An error occurred: {fault}")

補足:WSDL の特定の操作をさせる場合

例えば、Addという操作があり、2つの整数を受け取ってその和を返す場合は以下です。

from zeep import Client

# WSDLのURL
wsdl = "http://www.example.com/service?wsdl"

# クライアントの作成
client = Client(wsdl=wsdl)

# Add操作に対応するリクエストの送信
response = client.service.Add(a=10, b=20)

# レスポンスの表示
print(response)

つまり、上記では SOAP サーバー上にAddというメソッドがあり、その引数として10, 20を渡しているということになります。

requests ライブラリで SOAP にアクセスする方法

基本的にはzeepライブラリを使う方が簡単ですが、これが使えない場合にはrequestsライブラリで SOAP サーバーにアクセスしましょう。

こちらも順を追って解説します。

requests ライブラリのインストール

HTTP リクエストを行うため、requests ライブラリをインストールします。

pip install requests

インストールできたかを、以下のコマンドでチェック。

pip list | grep requests

バージョン情報が返ってくれば、インストール成功です。

基本的な使用方法

zeepではリクエスト用の XML を自動生成してくれましたが、requestsではちょっと手間がかかります。

import xml.etree.ElementTree as ET

import requests

# SOAPエンドポイントURL
url = "http://www.example.com/calculator"

# SOAPリクエストヘッダー
headers = {
    "Content-Type": "text/xml; charset=utf-8",
    "SOAPAction": "http://www.example.com/calculator/Add",
}

# SOAPリクエストボディ
body = """<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
               xmlns:xsd="http://www.w3.org/2001/XMLSchema"
               xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <Add xmlns="http://www.example.com/calculator">
      <a>10</a>
      <b>20</b>
    </Add>
  </soap:Body>
</soap:Envelope>"""

# リクエストを送信
response = requests.post(url, data=body, headers=headers)

# レスポンスの解析
root = ET.fromstring(response.content)

# 結果の抽出(名前空間の定義が必要)
namespace = {"ns": "http://www.example.com/calculator"}
result = root.find(".//ns:AddResponse/ns:result", namespace)

# 結果の表示
if result is not None:
    print("Result:", result.text)
else:
    print("No result found")

XML をちょっとラクに作る方法

手書きで XML を書くのは大変なので、xml.etree.ElementTreeモジュールで生成するのが良いと思います。

import xml.etree.ElementTree as ET

import requests

# SOAPエンドポイントURL
url = "http://www.example.com/calculator"

# SOAPリクエストヘッダー
headers = {
    "Content-Type": "text/xml; charset=utf-8",
    "SOAPAction": "http://www.example.com/calculator/Add",
}

# XML要素の作成
envelope = ET.Element("{http://schemas.xmlsoap.org/soap/envelope/}Envelope")
envelope.set("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance")
envelope.set("xmlns:xsd", "http://www.w3.org/2001/XMLSchema")
envelope.set("xmlns:soap", "http://schemas.xmlsoap.org/soap/envelope/")

body = ET.SubElement(envelope, "{http://schemas.xmlsoap.org/soap/envelope/}Body")
add = ET.SubElement(body, "Add")
add.set("xmlns", "http://www.example.com/calculator")

a = ET.SubElement(add, "a")
a.text = "10"
b = ET.SubElement(add, "b")
b.text = "20"

# XMLを文字列に変換
xml_request = ET.tostring(envelope, encoding="utf-8").decode("utf-8")

# リクエストを送信
response = requests.post(url, data=xml_request, headers=headers)

# レスポンスの表示
print(response.content)

レスポンスの解析は同様にできます。

import xml.etree.ElementTree as ET

# レスポンスの解析
root = ET.fromstring(response.content)

# 結果の抽出(名前空間の定義が必要)
namespace = {"ns": "http://www.example.com/calculator"}
result = root.find(".//ns:AddResponse/ns:result", namespace)

# 結果の表示
if result is not None:
    print("Result:", result.text)
else:
    print("No result found")

まとめ:SOAP も落ち着いて対応しよう!

「SOAP でアクセスして!」と言われると一瞬とまどいますが、落ち着いて対応すれば問題なく対応できるはずです。

ぜひ、本記事を参考に実装を進めてみてください。

本ブログのPython関連の記事は、以下のリンクからどうぞ。

» 参考:CFXLOG – Python に関する記事一覧

この記事が気に入ったら
フォローしてね!

シェア・記事の保存はこちら!

この記事を書いた人

karo@プログラマのアバター karo@プログラマ プログラマ

「書くことで人の役にたつ」をモットーに活動中。
本職はプログラマで、Python(Django)が得意。最近ではフロント側の技術に触れる機会も増えてきました。
基本情報技術者試験合格。

コメント

コメントする

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)