【Python】urllib.request / xml.etree.ElementTree を用いてHTTP API を利用する(Basic認証/POST/x-www-form-urlencoded/XML)
Python で HTTP API を利用する場合に、いつもの application/json ではなく、POST のコンテンツタイプが application/x-www-form-urlencoded で、response が XML で返却される API があり、標準モジュールを調べながら実装したので、備忘録として残しておく。
Python Version:3.8.5
urllib.request
Python から HTTP API を利用する場合、requests のような便利なモジュールがあるが、標準ライブラリーである urllib.request でも十分だと思い、今回は標準モジュールを使うこととした。
POST(application/x-www-form-urlencoded)
項目 | 設定 |
---|---|
認証 | Basic認証 |
コンテンツタイプ | x-www-form-urlencoded |
レスポンス | XML |
import urllib.request import base64 import ssl url = 'https://<---request URL--->' user = '<---user--->' password = '<---password--->' basic_auth = base64.b64encode('{}:{}'.format(user, password).encode('utf-8')) req_header = { 'Authorization': 'Basic ' + basic_auth.decode('utf-8'), 'Content-Type': 'application/x-www-form-urlencoded' } req_data = urllib.parse.urlencode({ 'name': 'TEST MAN', 'context': 'hogehoge' }) req = urllib.request.Request(url=url, data=req_data.encode('ascii'), method='POST', headers=req_header) context = ssl.SSLContext(ssl.PROTOCOL_TLSv1) try: with urllib.request.urlopen(req, context=context) as response: print(response.read()) except urllib.error.URLError as e: print(e.reason)
x-www-form-urlencoded は、"name=TEST MAN&context=hogehoge" のような形で、キーと値は「=」でキーと値の組となり、「&」で区切られてエンコードされる。また、キーや値の英数字以外の文字は、パーセントエンコーディングされる。
urllib.parse.urlencode({ 'name': 'TEST MAN', 'context': 'hogehoge'}) > name=TEST MAN&context=hogehoge
このようにエンコードすることで、文字列となる。ただし、Request.data は、Byte型かファイルオブジェクトでないといけないため、byte型に変更している。
data=req_data.encode('ascii')
また今回、以下のようなSSL認証エラーが発生した。
urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed
SSLContext を使うことで解消できたので、追加している。
POST(application/json)
import urllib.request import json url = 'https://<---request URL--->' req_header = { 'Content-Type': 'application/json', } req_data = json.dumps({ 'name': 'TEST MAN', 'context': 'hogehoge' }) req = urllib.request.Request(url=url, data=req_data.encode('ascii'), method='POST', headers=req_header) try: with urllib.request.urlopen(req) as response: print(json.loads(response.read())) except urllib.error.URLError as e: print(e.reason)
GET
QueryString を使って、リクエストパラメータを送る場合は、urllib.parse.urlencode
を利用する。
import urllib.request url = 'https://<---request URL--->' params = { 'foo': 123, } url_params = '{}?{}'.format(url, urllib.parse.urlencode(params) req = urllib.request.Request(url=url_params, method='GET') try: with urllib.request.urlopen(req) as response: print(response.read()) except urllib.error.URLError as e: print(e.reason)
xml.etree.ElementTree
XML を操作する場合は、xml.etree.ElementTree を使う。便利なモジュールとしては、xmljson や xmltodict などがある。
XMLの読み込み
import xml.etree.ElementTree as ET # ファイルから読み込む場合 tree = ET.parse('file_name.xml') root = tree.getroot() # 文字列 or バイト型のXMLを読み込む場合 root = ET.fromstring(xml)
データの読み取り
メソッド名 | 操作 |
---|---|
.tag | タグの名前を読み取る |
.attrib | 属性のデータを読み取る |
.text | テキストデータを読み取る |
子ノードの探索に関しては、様々なメソッドがあるので、Element オブジェクト を確認して欲しい。
array = [] for child in root.iter('data'): array += [{el.tag: el.text for el in child }] print(array)
上記では、<data>
配下の要素のタグ名をkey、テキストデータをvalueとして、辞書型とし、XMLを辞書配列に変更した例である。
まとめ
便利なモジュールがたくさんある中で、今回Pythonの標準モジュールを調べて使ってみた。標準モジュールで十分実装できると思えた。参考にしてもらえると嬉しい。
それでは、ステキな開発ライフを。