- 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関連の記事は、以下のリンクからどうぞ。
コメント