Amazonの商品発送メールに反応して配送状況をSafariで表示するワークフローとAppleScript

今の自分のMacBookは、ルールで賢く仕事するMacBookにしておいたので、購入先から商品発送しましたメールが届くと、自動的にSafariが宅配便の照会ページを開いてくれる。
多くのショップが伝票No.と照会ページのリンクを別々に記載している状況では、

  • 配送状況を照会するために伝票No.をコピーして、
  • 照会ページに移動して、
  • しかるべき場所に伝票No.をペーストする。

という手順が必要で、煩わしいと思っていた。だから個人的にはこの自動環境をかなり気に入っている。メールに配送伝票No.と宅配便会社名が記載されていれば、メールを受信するだけでSafariの照会ページが表示されるのだから。(たまには間違えて、関係ない番号を照会してしまうこともあるけど...。)

ところで、この宅配便の自動照会ルールは、Amazonの配送には反応しない。そもそも自動照会ルールを作ったきっかけが、メール本文中のリンクをクリックしただけでは配送伝票を照会できないことに不便を感じたから。Amazonの場合はリンクをクリックしていけば、どうにか照会ページには辿り着ける。

しかし、自動照会ルールの恩恵に慣れてしまった今、Amazonでの照会リンクのクリックさえ面倒に感じてきた。Amazonで配送状況を確認する場合、たぶん以下の手順が必要になると思う。

  • アカウントサービスを開いて、
  • 購入履歴を見る、
  • サインインする、
  • 注文履歴から目指す商品の、配送状況を確認する、
  • さらに詳細を確認したければ、配送状況の詳細を確認する。

最大5回のクリックが必要。一方、自動照会ルールなら、すでに照会ページは開いている。この差は大きい...。最も頻繁に利用するAmazonの照会が自動化されなくては、自分にとって快適な通販生活はあり得ないのだ...。(笑)

Amazonも自動照会ルールに組み込むべく、試行錯誤してみた。

宅配便会社の照会ページ

  • Amazonはどこかの宅配便会社を利用している訳で、配送方法の履歴を調べてみると以下のようになった。

以上のことを考慮して、以前作った自動照会ルールに追加を試みた。しかし...

  • 佐川メール便については...
    • 佐川のページでは照会できなかった。(お問い合わせのデータは登録されておりません)
    • そもそも、佐川メール便は照会できない仕様らしい。これは今時とっても不便に感じる。最低でも、配送が完了したかどうか(ポストに投函されたかどうか)くらいは知りたい。

カトーレックのページで照会するAppleScript


(* 照会_カトーレック *)
my search_katolec("771011888888")
on search_katolec(num) tell application "Safari"
tell window 1 --タブを操作するためにはwindowを指定する必要あり
{URL:"http://www6.katolec.com/tracking/amzn/tracking.aspx"} set current tab to make new tab with properties result
end tell
delay 1 --新規タブがロードされる待ち時間が必要
do JavaScript "
var element=document.getElementById('inputDenpyo');
element.value=" & num's quoted form & ";
document.trackingForm.submit();
" in document 1 --現在アクティブなページ(タブ)でjavascriptを実行する
end tell
end search_katolec

漏れなく照会するための作戦

  • 宅配便会社の照会ページだけに頼る方法では、佐川メール便のように照会できない仕様だったりして、不便を感じることもある。

ここで、Amazonで購入した商品の配送状況を追跡するベストな手段を見つけ出すために、照会できる・できない条件を見直してみた。

  • Amazon自身が発送する商品は...
    • Amazonの配送状況の確認ページで必ず照会できる。
    • 宅配便会社のページでは、照会できる場合と、できない場合がある。
    • 例:カトーレック=照会OK、佐川メール便=照会NG。
    • 商品発送メールの件名:Amazon.co.jp ご注文の発送 (123-1234567-1234567)
  • Amazonマーケットプレイスの出品者が発送する商品は...
    • Amazonの配送状況の確認ページでは照会できない。
    • 宅配便会社のページなら照会できる。
    • 商品発送メールの件名:Amazon.co.jp ご注文商品の発送 (#123-1234567-1234567)
    • 商品発送メールは、Amazon・出品者の両方から通知され、どちらにも伝票No.が記載されている。

Amazonのページで照会する作戦

  • 何はともあれ、伝票No.からAmazonの配送状況の確認ページを開くスクリプトが必要になる。
配送状況を確認するURL
  • 太字の部分がパラメーターとして、条件によって変化する値。
https://www.amazon.co.jp/gp/css/history/orders/view.html/ref=oss_track_no_js?trackShipmentID=DD7XXXXXX&trackOrderID=123-1234567-1234567#tracking-DD7XXXXXX
配送状況の詳細を確認するURL
  • 配送状況の詳細を確認するページは開けるが...
    • 詳細ページでは、商品名が載っていない。
    • 発送日が常に1970/1/1になってしまう。
    • latestArrivalDate・shipmentDateもちゃんと設定すれば改善されると思う。
    • しかし、その値はどこから引っ張ってくるのだろう?
https://www.amazon.co.jp/gp/css/shiptrack/view.html?addressID=npllsXXXX&trackingNumber=123456789012&latestArrivalDate=0000000000&shipMethod=SAGAWA_MAIL&orderID=123-1234567-1234567&ref=&shipmentDate=0000000000
  • 手っ取り早く目的を達成するためには、Amazonの注文番号から配送状況を確認するURLを生成するスクリプトを作れば良さそう。
  • しかし、それでは自分のMacBook以外の環境では役に立たないスクリプトになってしまう可能性がある。
    • trackShipmentID・addressIDなどが、ユーザーや利用マシンによって変化する可能性があるので。
  • たった1台のマシン専用のコードを書くというのは、コードを書く人として、できる限り避けたい、という思いがある。
  • それにしても、Amazonの配送状況の確認をするためのパラメーターは多い。伝票No.だけでOKな宅配便会社とは対照的である。
  • おそらく、Amazonではログインして、リンクを辿って照会することを想定している。(URLでダイレクトに照会することは想定されていないのだ)
  • であれば、アカウントサービスのページからリンクを辿る手作業を忠実に再現した方が、あらゆる環境で利用するには都合が良さそうな気がしてきた。
  • MacBookの中には、OSX標準でAutomator君が居る。
  • Automator君でGUIの操作を記録して、再現させれば、ほとんどのことは自動操作可能になる。
  • 早速やってみた。

Automatorで記録した操作をAppleScriptに変換する

  • 例えば、「注文履歴を見る」ボタンを押す操作をAutomatorで記録して、ドラッグ&ドロップすると...

  • 以下のように、「注文履歴を見る」ボタンを押す操作がAppleScriptに展開されるのだ。


  • 「注文履歴を見る」ボタンを押す操作自体は、おそらく以下の部分のコードとして表現されていると想像できる。
    • click image 1 of UI Element 30 of UI Element 1 of scroll area 1 of group 3 of window 1 of application process "Safari"
  • しかし、このコードをそのまま実行したのでは、うまくボタンが押されないことが多い。
  • 幾度か試行錯誤していると、普遍的な部分と、条件によって変化する部分があることに気付く。
  • どうも、UI Element 30の部分が、実行の度にUI Element 26, 31, ...などに変化しているのだ。
  • なぜ変化するのか、どんな条件でその値になるのかは分からない。
  • でも、変化するのであればその部分をすべて調べて、目指す「注文履歴を見る」ボタンの時だけクリックするようにしてみた。
  • このページでは「注文履歴を見る」ボタンはたった1つしかないので、その他の無効なオブジェクト参照はすべてエラーになる。


tell application "System Events"
tell UI element 1 of scroll area 1 of group 3 of window 1 of application process "Safari"
repeat with a_element in UI elements
tell a_element
try
if image 1's description is "注文履歴" then
click image 1
end if
end try
end tell
end repeat
end tell
end tell

  • これで、UI Element 30の部分が変化しても、確実に「注文履歴を見る」ボタンを押せるようになった。
  • ところで、webページを完全に表示するまでには、読み込むための時間が必要である。
  • 読み込み途中で上記スクリプトを実行しても、「注文履歴を見る」ボタンがまだ存在しなかったりして、エラーになる。
  • エラーの1秒後に完全なアカウントサービスのページが表示されても、「注文履歴を見る」ボタンは永久に押されないのだ。
  • そんな不運な状況を回避するための単純な方法としては、適当な待ち時間を作って、その後実行する手順が考えられる。
    • 具体的には、1行目に Delay 3 を追記して、3秒経過するのを待って、その後「注文履歴を見る」ボタンを押すのだ。
  • しかし、適当な待ち時間は3秒で良いのだろうか?もしかしたら、4秒必要かもしれない。あるいは2秒でも十分かもしれない。
  • 待ち時間が不足すればエラーになり、過剰であれば無駄な時間にイライラすることになる。
  • また、同じMacBookでも、その時のCPUの負荷や、回線の状況によって、最適な待ち時間は変化するはずだ。
  • だから固定的に Delay 3とするのは、あまりおすすめの方法とは言えない。
  • 現状のベストな方法は、Automator自身が生成するGUIスクリプティングAppleScriptにあった。
    • Automatorで操作を記録して、ドラッグ&ドロップして生成されるAppleScript
  • 最大の待ち時間を決めて、その待ち時間内はエラーが発生しても何度でも再試行する方法である。
  • それを参考に、以下のようにしてみた。


on run {input, parameters} (* Amazon注文履歴を見る *)
delay 1
repeat 4 times
delay 1
if my job() then exit repeat
end repeat
end run

on job() do shell script "/usr/local/bin/growlnotify -m '注文履歴を見る...' "
try
tell application "Safari" to set sign_in_url to document 1's URL
if sign_in_url begins with "https://www.amazon.co.jp/gp/css/homepage.html" then
tell application "System Events"
tell UI element 1 of scroll area 1 of group 3 of window 1 of application process "Safari"
repeat with a_element in UI elements
tell a_element
try
if image 1's description is "注文履歴" then
click image 1
return true
end if
end try
end tell
end repeat
end tell
end tell
end if
end try
false
end job

  • 最初に1秒待って、その後1秒おきに4回、再試行するのである。

これで無駄な時間を待たずに、かなり確実に「注文履歴を見る」ボタンを押せるようになった!

Amazonのページで照会するワークフロー

以上の要領で、必要な操作をアップルスクリプトに生成して、並べてみると以下のようになった。

アカウントサービスを開く


注文履歴を見る
  • すると、ページはこんな状態。

  • 「注文履歴を見る」ボタンを押す。


サインイン
  • すると、サインインを求められる。

  • ユーザー名とパスワードの自動入力を有効にしてあるので、自分のMacBookではすでに入力済みの状態になっている。
  • 「サインイン」ボタンを押す。


配送状況を確認する
  • すると、注文履歴のページへ移動する。

  • 目指す商品の「配送状況を確認する」ボタンを押す。


  • 実際にはボタンを押さずに、リンク先アドレスにジャンプしている。
  • 忠実にボタンを押す操作だと、JavaScriptによるページ遷移なしの処理になる。
  • すると、次の「配送状況の詳細を確認する」ページから戻った時に、配送状況の表示なしの状態に戻ってしまうのだ。
  • 一方、ページ遷移を伴うリンク先アドレスにジャンプする方法なら、戻った時の配送状況の表示も保持されるのだ。
  • また、ページ遷移を伴うリンク先アドレスにジャンプする方法だと、配送状況が見える位置まで自動的にスクロールしてくれるという利点もある。
  • 以下の操作は余分かもしれない。必要に応じて、自分で「配送状況の詳細を確認する」ボタンを押せば良いのだから。
  • しかし、AppleScriptで自動操縦する方法の記録として、せっかくなのでメモとして残してしまった。
配送状況の詳細を確認する
  • すると、配送状況が追記表示される。

  • さらに「配送状況の詳細を確認する」リンクも押す。


ブラウザの戻る操作
  • すると、配送状況の詳細ページへ移動する。

  • このままでは商品名が分からないので、一旦ブラウザの戻る操作を実行する。

  • これで、ブラウザの戻る・進む操作で、詳細ページとの間を素早く行き来できるのだ。


以上のワークフローは、「Amazon配送状況の詳細を確認する.workflow」として保存した。

ルールに組み込む

  • 以前の宅配便の自動照会のルールに、Amazonの処理を追加して、以下のようにしてみた。


property LIB : load script file ((path to scripts folder as text) & "_lib.scpt")
--Mail.appのルールで駆動する
using terms from application "Mail"
on perform mail action with messages theMessages for rule theRule
tell application "Mail"
repeat with aMessage in theMessages
set body to LIB's replace(aMessage's content, "'", "’") set title to LIB's replace(aMessage's subject, "'", "’") try
if my delivery_com(body) is "Amazon.co.jp" then
set the clipboard to my order_id(title) do shell script "open -b com.apple.AutomatorRunner $HOME/Library/Scripts/Amazon配送状況の詳細を確認する.workflow"
else
open location my query_url(my slip_no(body), my delivery_com(body)) end if
end try
end repeat
end tell
end perform mail action with messages
end using terms from

--メール本文から伝票No.を抽出する(ruby正規表現を利用)
--数字が12桁、あるいは4-4-4桁のパターンを抽出する(13桁以上の数字に含まれる場合は除外する)
-- 例:123456781234
-- 例:1234-5678-1234
on slip_no(str) LIB's do_ruby_jcode_u({"/\\D\\d{12}\\D|\\D\\d{4}\\-\\d{4}\\-\\d{4}\\D/ =~ " & quoted form of str, "$~"}) LIB's do_ruby_jcode_u({"/\\d{12}|\\d{4}\\-\\d{4}\\-\\d{4}/ =~ " & quoted form of result, "$~"}) end slip_no

on order_id(str) LIB's do_ruby_jcode_u({"/\\D\\d{3}\\-\\d{7}\\-\\d{7}\\D/ =~ " & quoted form of str, "$~"}) LIB's do_ruby_jcode_u({"/\\d{3}\\-\\d{7}\\-\\d{7}/ =~ " & quoted form of result, "$~"}) end order_id

--メール本文から宅配便の会社を調べる
on delivery_com(str) set delivery_names to {"Amazon.co.jp", "クロネコ", "ヤマト", "JPエクスプレス", "佐川", "sagawa", "ゆうバック"} repeat with a_name in delivery_names
if a_name is in str then
return a_name as text
end if
end repeat
end delivery_com

--伝票No.と宅配便の会社名から検索URLを生成する
on query_url(slip, company) try
"{" & ¬ "|クロネコ|:\"https://jizen.kuronekoyamato.co.jp/jizen/servlet/crjz.b.NQ0010?id=\"," & ¬ "|ヤマト|:\"https://jizen.kuronekoyamato.co.jp/jizen/servlet/crjz.b.NQ0010?id=\"," & ¬ "|西濃|:\"https://track.seino.co.jp/cgi-bin/gnpquery.pgm?GNPNO1=\"," & ¬ "|カンガルー|:\"https://track.seino.co.jp/cgi-bin/gnpquery.pgm?GNPNO1=\"," & ¬ "|佐川|:\"https://k2k.sagawa-exp.co.jp/p/web/okurijosearch.do?okurijoNo=\"," & ¬ "|sagawa|:\"https://k2k.sagawa-exp.co.jp/p/web/okurijosearch.do?okurijoNo=\"," & ¬ "|JPエクスプレス|:\"https://info.jpexpress.jp/confirm/confirmList.html?denpyoNo=\"," & ¬ "|ペリカン|:\"https://info.jpexpress.jp/confirm/confirmList.html?denpyoNo=\"," & ¬ "|ゆうパック|:\"http://tracking.post.japanpost.jp/service/singleSearch.do?searchKind=S002&locale=ja&SVID=023&reqCodeNo1=\"," & ¬ "|福山通運|:\"http://www4.fukutsu.co.jp/inq/INQJS120?toino=&toino=&toino=&toino=&toino=&toino=&toino=&toino=&toino=&toino=\"," & ¬ "|書留|:\"http://tracking.post.japanpost.jp/service/singleSearch.do?searchKind=S002&locale=ja&SVID=023&reqCodeNo1=\"," & ¬ "|翌朝10時郵便|:\"http://tracking.post.japanpost.jp/service/singleSearch.do?searchKind=S003&locale=ja&SVID=023&reqCodeNo1=\"," & ¬ "|EMS|:\"http://tracking.post.japanpost.jp/service/singleSearch.do?searchKind=S004&locale=ja&SVID=023&reqCodeNo1=\"" & ¬ "}'s"
set hash_code to result
run script hash_code & "|" & company & "|"
result & slip
end try
end query_url

  • 変更箇所は以下の部分。Amazonであれば、上記の「Amazon配送状況の詳細を確認する.workflow」を実行するのだ。
    • 現状は、Amazon.co.jpと注文番号を含むすべてのメールを照会する仕様になってしまっている。
    • 本来は、メールの件名から商品発送元が、Amazonであるか、マーケットプレイス出品者であるか判定して、無駄な照会を避けるようにするべき。(あとでやる)
  • AppleScriptからAutomatorへのAmazonの注文番号のやり取りに、クリップボードを利用している。
    • だから、コピー作業の真っ最中に、Amazonメールに反応してしまうと、ペーストした結果がAmazonの注文番号になってしまうのだ...。


...(中略)...
if my delivery_com(body) is "Amazon.co.jp" then
set the clipboard to my order_id(title) do shell script "open -b com.apple.AutomatorRunner $HOME/Library/Scripts/Amazon配送状況の詳細を確認する.workflow"
else
open location my query_url(my slip_no(body), my delivery_com(body)) end if
...(中略)...

  • また、Amazonの注文番号を抽出するハンドラも追加した。


on order_id(str)
LIB's do_ruby_jcode_u({"/\\D\\d{3}\\-\\d{7}\\-\\d{7}\\D/ =~ " & quoted form of str, "$~"})
LIB's do_ruby_jcode_u({"/\\d{3}\\-\\d{7}\\-\\d{7}/ =~ " & quoted form of result, "$~"})
end order_id

  • 実行するには、ユーザ・スクリプト・フォルダに、_LIB.scptもインストールしておく必要あり。

Mail.appのルール

  • Mail.appのルールは以下のようになっている。



これで快適な通販生活になりそうな予感!

  • 意味もなく、何かAmazonで買ってみたくなってきた...。

  • どうやら「配送状況を確認する」ボタンを押す操作が調子悪い...。(以下の部分)


  • 調べてみると、「WebページからリンクURLを取得」アクションで、URLの一部しか取得できないことがある。
  • しかし、何度か試していると、ちゃんとすべてのURLを取得できることもある。
  • Automatorのアクション自体に問題があるのかもしれないが、原因は分からない。
  • 「WebページからリンクURLを取得」アクションに頼らない方法を考えてみた。


on run {input, parameters} (* クリップボードorderIDを含む配送状況を確認する *)
delay 1
repeat 4 times
delay 1
if my job() then exit repeat
end repeat
end run

on job() do shell script "/usr/local/bin/growlnotify -m '配送状況を確認する...' "
tell application "System Events"
tell UI element 1 of scroll area 1 of group 3 of window 1 of application process "Safari"
repeat with a_table in tables
tell a_table
try
static text 1 of UI element (the clipboard as text) of group 1 of list 1 of UI element 1 of row 1
click image 1 of UI element 1 of group 1 of UI element 2 of row 2
return true
end try
end tell
end repeat
end tell
end tell
false
end job

  • GUIスクリプティングでは、「配送状況を確認する」ボタンのURLを取得することはできなかったのだが、
  • 同じテーブル内の注文番号なら取得できることに気付いた。
  • 注文番号へのオブジェクト参照を実行してエラーが発生しなければ、
  • そのテーブルの「配送状況を確認する」ボタンを押すことで、目指す商品の配送状況が表示されるのだ。

これで確実に「配送状況を確認する」ボタンを押せるようになった!

  • しかし、ページ遷移なしのJavaScript更新なので、詳細ページから戻った時に配送状況が閉じてしまう...。
  • ほとんどがAppleScriptになってしまったので、ワークフローにしておく価値がなくなってしまったかも。
  • すべてAppleScriptで書いておけば、引数のやり取りにクリップボードを使うような技も不要になる。(あとで書き直す)

以上のワークフローとAppleScriptは以下のリンクからダウンロードできる。