この記事では、Amazonの出品者向けのAPIであるAmazon MWS APIを使って、出品時にかかるAmazon手数料を取得する方法を紹介します。
最近AmazonのMWS APIをよく使うんだけど、公式が用意してくれてるクライアントライブラリにNode.jsのバージョンはない。
なので、Node.jsからMWS APIを使う場合はmws-productとかmws-sdk,mwsなど、心優しい先輩が作ってくれてるnpmモジュールのお世話になるのが楽だし確実。
なんだけど、Amazonマーケットプレイスでの出品時のAmazon手数料を取得できる’getMyFeesEstimate’なんかは、割と新しめなオペレーションのため対応しているモジュールが意外となかったりする。
今回、この’getMyFeesEstimate’が使えるモジュールが見つからなかったので、自作してみた。
細かい解説は面倒なので、それなりにアクセスがあって需要がありそうなら後日追記する。かも。
もくじ
準備
必要なモジュールをnpmからインストールする
今回のサンプルでは、以下のモジュールを使うのでnpmから入手しておいてください。
crypto
node.jsで暗号化とかハッシュといえばこのcrypto。
AmazonAPIにリクエストを送信する際、HmacSHA256を使って署名する必要があるのでcryptoのお世話になることにします。
単にソース内に
としてやればokのようです。
これで動かない場合のみnpm installしてみてください。
lodash
lodashはzip,zipWithなどの便利メソッドが用意されており、配列操作が何かと楽なので使ってます。
ただzip,zipWithとかぶっちゃけmap()で済むし、他もだいたいfilter(),reduce()で出来ると思うので、腕に覚えのある方なら要らないのかもしれない。でも僕はlodash好きだから使っちゃう。
moment
momentは時間の扱いが劇的に楽になるモジュールです。一度使うと手放せない。
今回はMWS API必須リクエストパラメーターのtimestampを作成するのに使います。
生のjsで時間を扱おうとすると何かと面倒が多く、指定形式にフォーマットされたタイムスタンプを作成するとかめんどくさすぎて無理なので、ここはぜひmomentを。
request
リクエスト送ってレスポンスもらうやつです。
https://www.npmjs.com/package/request
MWS API ProductsセクションのgetMyFeesEstimate.jsを叩いて手数料額を取得する
はじめにちょっと注意事項。
Amazon MWS APIのシークレットキー、セラーIDなどの機密情報は、上記のソースにベタ書きせずに、別途jsonファイルを作って管理するのがベターだろう。
特にGitでソースを管理している場合など、外部に漏れたらマズい情報をソースに乗せていると間違えてうっかり晒してしまうこともあるので注意。
今回は’amazon_credential.json’という名前で認証情報を管理するjsonファイルを作り、そこから読み込むようにしている。
その上で.gitignoreなるものでGitの管理に含めないファイル/ディレクトリを指定できるので、このamazon_credencialをGitに晒さないように設定しておくといいだろう。
1 2 3 4 5 6 |
{ 'SELLER_ID': 'YOUR_SELLER_ID', 'ACCESS_KEY_ID': 'YOUR_ACCESS_KEY_ID', 'SECRET_KEY': 'YOUR_SECRET_KEY', 'MARKETPLACE_ID': 'YOUR_MARKETPLACE_ID', } |
https://qiita.com/inabe49/items/16ee3d9d1ce68daa9fff
ソース:getMyFeeEstimate.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 |
// 必要なモジュールをimport const crypto = require('crypto'); const moment = require('moment'); const _ = require('lodash'); const request = require('request'); // Amazon MWS API の認証情報を別に作成した設定ファイルから読み込んでおくで const AMAZON_CREDENTIAL = require('./amzn-credential'); // 非推奨だけど認証情報をベタ書きで出来んこともない // const AMAZON_CREDENTIAL = { // 'SELLER_ID': 'YOUR_SELLER_ID', // 'ACCESS_KEY_ID': 'YOUR_ACCESS_KEY_ID', // 'SECRET_KEY': 'YOUR_SECRET_KEY', // 'MARKETPLACE_ID': 'YOUR_MARKETPLACE_ID', // }; // Amazon MWS APIのエンドポイント。たいていの人は.jpのはず const ENDPOINT = 'mws.amazonservices.jp'; // getMyFeesEstimate関数を外部から使えるようにしておくで module.exports = { getMyFeesEstimate, }; /** * Amazonマーケットプレイスでの販売手数料を取得する関数 * * @param {object} params APIに渡す任意リクエストパラメーターのオブジェクト * @return {String} result Amazonから返された結果のXML */ function getMyFeesEstimate(params){ return new Promise((resolve,reject) => { const timestamp = get_timestamp(); const identifier = moment().format('x'); const requied = { 'Action': 'GetMyFeesEstimate', 'AWSAccessKeyId': AMAZON_CREDENTIAL['ACCESS_KEY_ID'], 'FeesEstimateRequestList.FeesEstimateRequest.1.Identifier': identifier, 'FeesEstimateRequestList.FeesEstimateRequest.1.MarketplaceId': AMAZON_CREDENTIAL['MARKETPLACE_ID'], 'SellerId': AMAZON_CREDENTIAL['SELLER_ID'], 'SignatureMethod': 'HmacSHA256', 'SignatureVersion': '2', 'Timestamp': timestamp, 'Version': '2011-10-01', }; const optional = { 'FeesEstimateRequestList.FeesEstimateRequest.1.IdType': params.IdType, 'FeesEstimateRequestList.FeesEstimateRequest.1.IdValue': params.IdValue, 'FeesEstimateRequestList.FeesEstimateRequest.1.IsAmazonFulfilled': params.IsAmazonFulfilled, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.Amount': params.ListingPrice.Amount, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.ListingPrice.CurrencyCode': params.ListingPrice.CurrencyCode, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.Amount': params.Shipping.Amount, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Shipping.CurrencyCode': params.Shipping.CurrencyCode, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsNumber': params.Points.PointsNumber, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsMonetaryValue.Amount': params.Points.PointsMonetaryValue.Amount, 'FeesEstimateRequestList.FeesEstimateRequest.1.PriceToEstimateFees.Points.PointsMonetaryValue.CurrencyCode': params.Points.PointsMonetaryValue.CurrencyCode, }; const section_name = '/Products/2011-10-01'; const data = _.merge(requied, optional); const query = getQueryRequestStr(data); const signature = getSignature(query, section_name); sendRequest(query, signature, section_name) .then((result) => { console.log(JSON.stringify(result, undefined, 2)); resolve(result); }) .catch((err) => { console.log(err); reject(err); }); }); } /** * Amazon MWS APIに渡す任意・必須パラメーターを受け取り、リクエストクエリ文字列を作成する。 * * @param {object} params APIに渡すパラメーターのオブジェクト * @return {String} query 整形されたリクエストクエリ文字列。 */ function getQueryRequestStr(params) { const data = params; const ordered_keys = _.sortBy(Object.keys(data)).map((x) => encodeURIComponent(x)); const ordered_values = ordered_keys.map((k) => data[k]).map((x) => encodeURIComponent(x)); const query = _.zipWith(ordered_keys, ordered_values,(k,v) => `${k}=${v}`).join('&'); return query; } /** * 署名を作成する。 * * @param {String} query リクエストクエリ文字列。 * @param {String} section_name 利用するAPIセクションの名前。 * @return {String} signature 署名文字列。 */ function getSignature(query, section_name){ const encoding_str = `POST\n${ENDPOINT}\n${section_name}\n${query}`; const hmac = crypto.createHmac('sha256', AMAZON_CREDENTIAL.SECRET_KEY) .update(encoding_str) .digest('base64'); const signature = encodeURIComponent(hmac); return signature; } /** * Amazon MWS APIにPOST形式でリクエストを送信し、レスポンスボディを返す。 * * @param {object} params APIに渡すパラメーターのオブジェクト * @return {String} query 整形されたリクエストクエリ文字列。 */ function sendRequest(query, signature, section_name){ return new Promise((resolve,reject) => { try{ const headers = { 'Content-Type':'My Desktop Seller Tool/1.0 (Language=nodev7.8.0; Platform=Macintosh)' }; const options = { url: `https://${ENDPOINT}${section_name}?${query}&Signature=${signature}`, method: 'POST', headers }; //リクエスト送信 request(options, (error, response, body) => { if(error){ return reject(error); } resolve(body); }); }catch(err){ reject(err); } }).catch((err) => { console.error(err); }); } /** * Amazon MWS API必須パラメーターのフォーマット済みタイムスタンプを返す。 * * @return 整形されたタイムスタンプ文字列。 */ function get_timestamp(){ return moment().utc().format('YYYY-MM-DDTHH:mm:ss\\Z'); } |
コンソールから実行
node > const params = {
IdType: ‘ASIN’,
IdValue: ‘B000000000’, // 任意のASIN
IsAmazonFulfilled: ‘true’, // FBAを利用しているかどうか
ListingPrice: {
Amount: ‘5000’, // 商品の販売価格
CurrencyCode: ‘JPY’, // 通貨単位(日本円)
},
Shipping: {
Amount: ‘0’, // 配送料
CurrencyCode: ‘JPY’,
},
Points: {
PointsNumber: ‘0’, // 付与するポイント
PointsMonetaryValue: {
Amount: ‘0’,
CurrencyCode: ‘JPY’,
},
},
};
node > const gmfe = require(‘./getMyFeesEstimate.js’);
node > gmfe.getMyFeesEstimate(params);
実行結果
successの場合、こんな感じでXMLが返ってくる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 |
<GetMyFeesEstimateResponse xmlns="http://mws.amazonservices.com/schema/Products/2011-10-01"> <GetMyFeesEstimateResult> <FeesEstimateResultList> <FeesEstimateResult> <FeesEstimate> <TotalFeesEstimate> <CurrencyCode>JPY</CurrencyCode> <Amount>896.00</Amount> </TotalFeesEstimate> <TimeOfFeesEstimation>2017-10-03T18:00:00.000Z</TimeOfFeesEstimation> <FeeDetailList> <FeeDetail> <FeeAmount> <CurrencyCode>JPY</CurrencyCode> <Amount>750.00</Amount> </FeeAmount> <FinalFee> <CurrencyCode>JPY</CurrencyCode> <Amount>750.00</Amount> </FinalFee> <FeePromotion> <CurrencyCode>JPY</CurrencyCode> <Amount>0.00</Amount> </FeePromotion> <FeeType>ReferralFee</FeeType> </FeeDetail> -- 中略 -- <FeesEstimateIdentifier> <MarketplaceId>A1VC38T7YXB528</MarketplaceId> <IdType>ASIN</IdType> <SellerId>sellerid</SellerId> <IsAmazonFulfilled>true</IsAmazonFulfilled> <SellerInputIdentifier>123456789</SellerInputIdentifier> <IdValue>B00000000</IdValue> <PriceToEstimateFees> <ListingPrice> <CurrencyCode>JPY</CurrencyCode> <Amount>5000</Amount> </ListingPrice> <Shipping> <CurrencyCode>JPY</CurrencyCode> <Amount>0</Amount> </Shipping> <Points> <PointsMonetaryValue> <CurrencyCode>JPY</CurrencyCode> <Amount>0</Amount> </PointsMonetaryValue> <PointsNumber>0</PointsNumber> </Points> </PriceToEstimateFees> </FeesEstimateIdentifier> <Status>Success</Status> </FeesEstimateResult> </FeesEstimateResultList> </GetMyFeesEstimateResult> <ResponseMetadata> <RequestId>reqid</RequestId> </ResponseMetadata> </GetMyFeesEstimateResponse> |
なげえ!!
が、この場合必要になるのは
以下の
部分だけでしょう。このamountで返される数字が手数料額の合計になります。
その他、手数料の内訳などのデータも帰ってくるので、必要に応じて。
取得したxmlを見やすく加工する
ご覧の通り、Amazonから返されたxmlはそのままでは非常に見づらい&扱いづらいので、xmlやhtmlをjQueryライクに読み込むことができるモジュール’cheerio’で使いやすくしましょう。
cheerioを使えば、
みたいな感じで、jQueryのようなノリでxml内のデータにアクセスできるので便利。
ちなみに、クローリング・スクレイピングでめっちゃよく使われるcheerio-httpcliはcheerioの独自拡張版で、別物なので注意。
cheerioのインストール
こちらもnpmで。
https://www.npmjs.com/package/cheerio
サンプル:cheerioでレスポンスxmlから手数料額、販売額を抽出してみる
上で紹介したgetMyFeesEstimate.jsのgetMyFeesEstimate関数を以下のように変更する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
function getMyFeesEstimate(params){ return new Promise((resolve,reject) => { const timestamp = get_timestamp(); const identifier = moment().format('x'); <中略> sendRequest(data, query, signature, section_name) .then((result) => { // 結果のxmlをcheerioに読み込む。そしたら$('セレクタ名')の形で要素にアクセス可能に const $ = cheerio.load(result) // 結果はオブジェクトに格納 const results = { total_fee: $('TotalFeesEstimate Amount').text(), selling_price: $('ListingPrice Amount').text(), }; console.log(JSON.stringify(results, undefined, 2)); resolve(result); }) .catch((err) => { console.log(err); reject(err); }); }); } |
実行結果
“total_fee”: “896.00”,
“selling_price”: “5000”
}
だいぶマシやな!
「ここ間違うてるやんけ!」「なにやってるかわからん!」「ちゃんと説明しろ!」などのご意見・ご要望は@sutaba_macにリプ飛ばしていただくか、お問い合わせフォームなどからお願いします。バイバイ!
参考にしたもの
Amazon マーケットプレイスWebサービス (MWS) APIから注文情報を取得する方法
https://tech.torico-corp.com/blog/amazon-marketplace-mws-api/
Amazon MWS のクライアントライブラリの使用
http://docs.developer.amazonservices.com/ja_JP/dev_guide/DG_ClientLibraries.html
Amazon MWS スクラッチパッド
https://mws.amazonservices.jp/scratchpad/index.html