UWSCRで疑似APIっぽく日本郵便の追跡ページをJSON形式で取得する
UWSCRを使って、日本郵便の追跡ページから配達状況および履歴情報を取得し、JSON形式で出力する処理を作成しました。
はじめに
従来のUWSCでは、JSONの取り扱いやHTMLのパース処理はほぼ不可能でした。
たとえばHTMLから特定の要素を取得するといった処理を行うには、正規表現でごり押しするか、外部ツールに頼る必要がありました。
しかし、UWSCRでは ParseHTML()
によってHTMLをDOMとして解析することも可能になっています。
また、UObject
を使ったオブジェクト記法が導入されており、JSON形式のデータを構造的に扱うことができます。
これにより、APIが用意されていないWebサービスからも、HTMLベースで必要な情報を安全に抽出し、構造化して扱えるようになりました。
本記事ではその一例として、日本郵便の追跡ページをパースしてAPIのような形でデータを扱う処理を紹介します。
処理の目的
- 日本郵便の追跡ページにアクセスし、配達状況と履歴を自動で取得したい
- 情報をJSON形式に整形して、後続処理や通知に使いたい
- 公式APIが存在しないサービスを、UWSCRの機能で補完したい
処理の流れ
-
webrequest()
でHTMLを取得し、ParseHTML()
に渡してDOM化します - 「配達状況詳細」テーブルから、項目と値のペアを取得します
- 「履歴情報」テーブルから、複数行に分かれた配送履歴を抽出します
- 抽出結果をJSON構造にまとめて返します
使用例
shippingNumber = "123456789123"
print JapanPostTrackingAPI(shippingNumber)
function JapanPostTrackingAPI(shippingNumber)
//JSONフォーマット
json = @{
"statusCode": "",
"status": "",
"message": "",
"data":{
"trackingNumber": "",
"packageType": "",
"services": "",
"size": "",
"deliveryDate": "",
"timeSlot": "",
"deliveryOffice": "",
"multiPackageCount": "",
"trackingHistory":[]}
}@
//trackingHistory内(履歴データ1件分)のフォーマット
trackingJson = @{
"date": null,
"status": null,
"detail": null,
"office": null,
"region": null,
"zipcode": null
}@
//日本郵便のトラッキングページを取得し、HTMLをパース
url = "http://tracking.post.japanpost.jp/service/singleSearch.do?searchKind=S002&reqCodeNo1=" + shippingNumber + "&locale=jp"
request = webrequest(url)
root = ParseHTML(request)
//「配達状況詳細」テーブルの各項目(th)とその値(td)を取得して、対応するJSONキーにマッピング
th = root.first('table[summary="配達状況詳細"]').find('th')
td = root.first('table[summary="配達状況詳細"]').find('td')
fieldNames = ["お問い合わせ番号", "商品種別", "付加サービス", "サイズ", "お届け指定日", "指定時間帯", "配達予定局", "複数個口数"]
jsonKeys = ["trackingNumber", "packageType", "services", "size", "deliveryDate", "timeSlot", "deliveryOffice", "multiPackageCount"]
for i = 0 to length(th.outerHTML) - 1
label = th[i].textContent
for n = 0 to length(fieldNames) - 1
if label = fieldNames[n] then
json.data[jsonKeys[n]] = td[i].textContent
break
endif
next
next
//「履歴情報」テーブルの各行から、配送履歴を抽出
tr = root.first('table[summary="履歴情報"]').find('tr')
th = root.first('table[summary="履歴情報"]').find('th')
historyLabels = ["状態発生日", "配送履歴", "詳細", "取扱局", "県名等", "郵便番号"]
historyKeys = ["date", "status", "detail", "office", "region", "zipcode"]
for i = 0 to length(tr.outerHTML) - 1 step 2
//取得したいtrが2行に分かれているため強制的にマージ→パースしてコレクション化する
td = ParseHTML('<table>' + tr[i].innerHTML + tr[i + 1].innerHTML + '</table>').find('td')
if length(td.outerHTML) > 0 then
for n = 0 to length(th.outerHTML) - 1
label = th[n].textContent
for m = 0 to length(historyLabels) - 1
if label = historyLabels[m] then
trackingJson[historyKeys[m]] = td[n].textContent
break
endif
next
next
endif
//履歴情報データの追加
if trackingJson.date <> null then
json.data.trackingHistory += trackingJson
endif
//履歴情報データJSONの初期化
for key in historyKeys
trackingJson[key] = null
next
next
//照会結果テーブルが存在する場合はエラーとみなして、ステータスとメッセージを設定
if length(root.find('table[summary="照会結果"]').outerHTML) > 0 then
json.statusCode = "400"
json.status = "error"
json.message = root.first('table[summary="照会結果"]').first("font").text
json.data = null
else
json.statusCode = "200"
json.status = "success"
json.message = "お問い合わせ情報を取得しました"
endif
result = ToJson(json, True)
fend
検証環境:UWSCR(x64) Ver. 1.1.2
コードのポイント
JSON構造の初期化
返却用のJSONは、ステータス情報と配達データで構成されています。
履歴情報(trackingHistory
)は配列であり、1件分のテンプレート(trackingJson
)を使い回して追加していきます。
なお、テンプレートは参照型のため、都度 null
初期化を行わないと全件が同じ内容になる恐れがあります。
HTMLのパース処理について
UWSCRの ParseHTML()
を使用すると、HTMLをDOMオブジェクトとして解析できます。
ただし、.find
で得られるのは NodeCollection
型であり、length()
がそのまま使えないため、ループ回数を取得するには .outerHTML
など配列を返すプロパティを経由する必要があります。
length(th.outerHTML)
また、履歴情報の <tr>
が2行に分かれているため、1件分の情報を取得するにはHTMLを結合してから再度 ParseHTML()
に渡す必要があります。
UWSCRではHTML文字列の再構築と再パースが比較的簡単に行えるため、以下のような処理で対応しています。
td = ParseHTML('<table>' + tr[i].innerHTML + tr[i + 1].innerHTML + '</table>').find('td')
このように、一度文字列として <tr>
2行分を結合し、仮の <table>
タグで囲んだ上で再度 ParseHTML()
に渡すことで、
2行分を1セットの td
要素として取得できるようにしています。
UWSCRでは、こうした再パース処理が比較的容易に行えるため、複雑なテーブル構造にも対応しやすい特徴があります。
エラー判定の扱い
「お問い合わせ番号が見つかりません」や「情報が登録されていません」といったケースでは、通常の配達状況テーブルではなく、 別の「照会結果」テーブルが表示される構造になっています。
UWSCRではこのテーブルの存在を root.find('table[summary="照会結果"]')
で検出し、 存在している場合は "statusCode": "400"
、"status": "error"
としてエラー扱いとしています。
また、エラーメッセージ自体も画面内の <font>
要素から取得し、"message"
に格納しています。
所感
UWSCRはGUI自動化に強いツールですが、構文や機能の進化によりJSONやHTMLの構造的な扱いも可能になりました。
これにより、APIが用意されていないWebサービスに対しても、情報取得〜整形〜通知の一連の自動化を完結させることができます。
本記事で紹介した処理は、あくまで一例ですが、構造が安定しているページであれば同様の手法で応用が可能です。
おわりに
UWSCRでは、Webページから必要な情報を「画面を操作せずに取得する」ことが可能です。
従来のUWSCとは異なり、HTMLの要素抽出やJSON形式での整形など、スクリプト単体で完結できる場面が増えています。
GUI自動化以外にも、「外部サービスの情報を取得して処理する」といった用途にUWSCRを活用するきっかけになれば幸いです。
Discussion