はじめに
ねえ、おとん、
楽天市場のお買い物リストが自動的にできて便利になったんだけど、Amazonでも同じことできない?
できるよ。
Amazonからの注文確認メールの内容を解析して、リストに追加すればいいだけだからね。
Amazonからのメールをいちいち確認するのも、注文リストを手で作るのも面倒だから、ちょっと作ってくれる?
承知しました。
ということで、Amazonのお買い物一覧の自動作成も作ることになりました。
対象読者
ここで紹介する内容は、以下の条件を満たす方が対象となります。
対象読者
- Amazonで注文することがある
- Amazonの注文内容確認メールをGmailで受け取っている
- Amazonの注文内容をスプレッドシートに自動追加したい
Gmailの内容をGoogle Apps Scriptで解析して、Google Driveに購入品一覧をスプレッドシートに自動追記することを考えます。
また、以下の6つの記事を確認しておくと、理解が早いと思います。
ご存じの方は、読み飛ばしてください。
Google Apps Scriptを使って自動化しよう
GmailにGoogle Apps Scriptからアクセスする方法
Google Apps Scriptで繰り返し実行させる方法
ライブラリ化について
注文リストファイル項目追加ライブラリ
楽天市場注文リストの自動生成
Amazonからの注文内容をスプレッドシートに自動追記
Gmailから該当メールを抽出する部分、処理済みメールにラベルを付ける部分は、これまで見てきたカレンダーに登録する処理と同様です。
主な違いは以下の2点です。
- Gmailでメールを抽出する際の検索文字が、Amazonからの注文確認メール
- メール本文から注文内容を抽出方法がAmazonからの注文確認メールに特化している
- メールから抽出した内容をスプレッドシートの最終行に追記する
複数同時に商品を購入した際に、総計は取得できますが、まだ各商品の価格が取得できていません。今後アップデートします。
処理概要
Amazonを利用すると以下のような利用明細をメールで受け取ることができます。
そして、以下のようにスプレッドシートの最下行に注文内容を自動追加します。
スプレッドシートに利用内容を登録するために、以下の処理を考えます。
- Amazonからの注文確認メールで未処理のメールを抽出
- 注文確認メールから、商品、値段、数量、送料、使用ポイント額、使用クーポン額、支払額、獲得ポイント、ショップ名を抽出
- スプレッドシートの最終行に②で得た情報を追記
- 注文確認メールに処理済みラベルを付ける
そして、この処理を定期的に行わせます。
未処理メールの抽出
楽天市場からの注文確認メールで、未処理のメールの抽出は以下の検索文字列で実現します。
メールの抽出条件の構文は、Gmailの抽出条件に設定できる構文と同じです。
var LABEL = '自動処理済'; // 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var SEARCH_QUERY = 'is:unread -label:' + LABEL + ' from:digital-no-reply@amazon.co.jp subject:amazon.co.jp注文';
処理済みを識別するために、処理完了後に該当メールのラベルに「自動処理済」を付けます。
そのため、抽出条件は以下の4つとなります。
- 未読であること(is:unread)
- 「自動処理済」のラベルが付いていないこと(-label:自動処理済)
- Amazonのメールであること(from:digital-no-reply@amazon.co.jp)
- Amazonの注文確認メールであること(subject:amazon.co.jp注文)
注文内容抽出
注文確認メールをシンプルテキストで取り出すと以下のようになります。(一部抜粋)
ここから、 商品、値段、数量、送料、使用ポイント額、使用クーポン額、支払額、獲得ポイント、ショップ名を抽出します。
関谷 様 ご購入ありがとうございます。購入したKindle本はクラウドに保存され、「コンテンツと端末の管理」から確認できます。 コンテンツと端末の管理: https://www.amazon.co.jp/gp/digital/fiona/manage/ref=TE_M1YKL#All 領収書をご希望の場合は、お客様ご自身で印刷することができます。詳しくは、ヘルプページの「領収書を印刷する」をご覧ください。 領収書を印刷する: https://www.amazon.co.jp/gp/help/customer/display.html?nodeId=201894740&ref=kc_tmail_receive ............................................................................ 注文情報 Eメールアドレス: ayikes@gmail.com 注文合計: ¥ 1,551 ............................................................................ 注文内容 注文番号: D01-2071330-8649039 商品の小計: ¥ 1,553 Amazonポイント: -¥ 2 </tr> ........................ 注文合計: ¥ 1,551 ............................................................................ 社畜男はB人お姉さんに助けられて―― : 2 (モンスター文庫) Kindle版 販売: Amazon Services International, Inc. 社畜男はB人お姉さんに助けられて―― : 3 (モンスター文庫) Kindle版 販売: Amazon Services International, Inc. ............................................................................
シンプルテキストで抽出すると、各商品の価格が取れないことがわかります。なので、Htmlメールを直接処理するよう修正する予定です。
注文内容の抽出部分は以下のコードで処理しています。
綺麗にまとまりませんでしたが、文字列処理なのでしょうがないかと。
基本的には、キーワードを見つけて、値を抽出することを繰り返しています。
var rows = body.split("\n");
for (var i in rows) {
var row = rows[i];
// 情報抽出
if(row.match(/^注文番号: /)){
order_number = row.replace('注文番号: ', '');
}
else if(row.match(/^Amazonポイント:/)){
point_used = row.replace('Amazonポイント:', '').replace('¥', '');
}
else if(row.match(/^注文合計:/)){
payment = row.replace('注文合計:', '').replace('¥', '');
}
else if(order_number != null && payment != null && row.indexOf(BORDER) >= 0){
flgItem *= -1;
}
else{
if(flgItem > 0){
if(row.match(/販売: /)){
shopName = row.replace('販売: ', '');
// 価格情報取得段階でスプレッドシートに登録する
Logger.log('itemName=' + itemName + ' shopName=' + shopName);
libAddOrderToList.registOderInfoToSpreadSheet(
'test', '', startTime, 'Amazon', itemName, price, 1, shopName);
itemName = null;
}
else{
row = row.replace('\r', '');
if(row.length > 0 && itemName == null){
itemName = row;
}
else if(row.length > 0 && itemName != null){
itemName += ' ' + row;
}
}
}
}
}
//Logger.log('order_number=' + order_number);
//Logger.log('point_used=' + point_used);
//Logger.log('payment=' + payment);
// 追加情報をスプレッドシートに登録
if(shipping == null) shipping = 0;
if(point_used == null) point_used = 0;
if(point_get == null) point_get = 0;
libAddOrderToList.registOderInfoToSpreadSheetSub(
'test', '', shipping, point_used, 0, payment, point_get);
スプレッドシート登録
スプレッドシートへの登録は、libAddOrderToListライブラリの関数を呼び出すことで登録します。
// 価格情報取得段階でスプレッドシートに登録する
libAddOrderToList.registOderInfoToSpreadSheet(
'test', '', startTime, 'Amazon', itemName, price, 1, shopName);
// 追加情報をスプレッドシートに登録
libAddOrderToList.registOderInfoToSpreadSheetSub(
'test', '', shipping, point_used, 0, payment, point_get);
スプレッドシート名は「test」となります。※お好みで変更してください。
libAddOrderToListについては以下の記事を参照ください。
全てのコード
/*
* Amazonの注文内容をスプレッドシートに追記する
*
* 2021/11/01 Created by N.Sekiya
*/
// 処理済み後に付けるラベル名(ラベルが存在しなければ自動的に作られる)
var LABEL = '自動処理済';
// GMail検索文字列(Amazonからの注文確認メール)※未読でラベルなしが条件
var SEARCH_QUERY = 'is:unread -label:' + LABEL + ' from:digital-no-reply@amazon.co.jp subject:amazon.co.jp注文';
// 検索文字列
var BORDER ='............................................................................';
function amazonAddOrderList() {
// デフォルトカレンダーを取得
//var calendar = CalendarApp.getDefaultCalendar();
var threads = GmailApp.search(SEARCH_QUERY, 0, 1);
if (threads.length === 0) {
Logger.log('メールが見つかりません');
return;
}
for(var k in threads){
var thread = threads[k];
var messages = thread.getMessages();
for (var j in messages){
var message = messages[j];
var body = message.getPlainBody(); // HtmlメールからPlain textの本文を取得する
var startTime = message.getDate();
Logger.log('subject=' + message.getSubject());
Logger.log("body=" + body);
var order_number = null;
var itemName = null;
var shopName = null;
var price = null;
var count = null;
var payment = null;
var shipping = null;
var point_used = null;
var point_get = null;
var flgItem = -1;
// 注文メールの内容確認
var rows = body.split("\n");
for (var i in rows) {
var row = rows[i];
// 情報抽出
if(row.match(/^注文番号: /)){
order_number = row.replace('注文番号: ', '');
}
else if(row.match(/^Amazonポイント:/)){
point_used = row.replace('Amazonポイント:', '').replace('¥', '');
}
else if(row.match(/^注文合計:/)){
payment = row.replace('注文合計:', '').replace('¥', '');
}
else if(order_number != null && payment != null && row.indexOf(BORDER) >= 0){
flgItem *= -1;
}
else{
if(flgItem > 0){
if(row.match(/販売: /)){
shopName = row.replace('販売: ', '');
// 価格情報取得段階でスプレッドシートに登録する
Logger.log('itemName=' + itemName + ' shopName=' + shopName);
libAddOrderToList.registOderInfoToSpreadSheet(
'test', '', startTime, 'Amazon', itemName, price, 1, shopName);
itemName = null;
}
else{
row = row.replace('\r', '');
if(row.length > 0 && itemName == null){
itemName = row;
}
else if(row.length > 0 && itemName != null){
itemName += ' ' + row;
}
}
}
}
}
//Logger.log('order_number=' + order_number);
//Logger.log('point_used=' + point_used);
//Logger.log('payment=' + payment);
// 追加情報をスプレッドシートに登録
if(shipping == null) shipping = 0;
if(point_used == null) point_used = 0;
if(point_get == null) point_get = 0;
libAddOrderToList.registOderInfoToSpreadSheetSub(
'test', '', shipping, point_used, 0, payment, point_get);
/* Googleカレンダーに登録
libCtrlCalendar.registCalendar(
calendar, 'Amazon注文',
startTime, endTime, contents, CalendarApp.EventColor.GREEN);
libCtrlMail.putLabel(thread);
*/
// スレッドの最初のメッセージを処理したら次のスレッドを処理する
break;
}
}
}
使用しているライブラリは以下点です。
- メール処理:libCtrlMail
- スプレッドシート処理:libAddOrderToList
Googleカレンダーの登録処理をコメントアウトしていますが、有効にすることでカレンダー登録と注文一覧生成を同時に処理できるようになります。この場合、libCtrlCalendarも必要になります。
繰返し実行
正しく動作することを確認したら、繰り返し実行できるよう設定します。
繰り返し実行には、トリガーの設定を行います。設定方法については、以下の記事を参照ください。
繰り返し実行する間隔は、急ぐ必要のない処理なので5分おきにします。
最後に
いかがでしたでしょうか。
まだまだ自動処理は作り続ける予定ですので、みなさまの参考になり、少しでも面倒な手間が省ければと思います。
そのうち、作りためた自動処理をもとに、IT秘書さん、IT家政婦さんとして整理しようと思っています。
では、今日も良い一日を。