1 | // Amazonの注文履歴をTSV形式で出力するスクリプト |
1 | // Amazonの注文履歴をTSV形式で出力するスクリプト |
2 | // |
2 | // |
3 | // 2015-01-01 時点での DOM 構造に対応, GoogleCrome, Opera でテスト済。 |
3 | // 2015-01-01 時点での DOM 構造に対応, GoogleCrome, Opera でテスト済。 |
4 | // formatEntry関数を書き換えれば自由な書式で出力できます。 |
4 | // formatEntry関数を書き換えれば自由な書式で出力できます。 |
5 | // |
5 | // |
6 | // 参考: |
6 | // 参考: |
7 | // - Amazonの注文履歴をCSV形式にして出力するスクリプト |
7 | // - Amazonの注文履歴をCSV形式にして出力するスクリプト |
8 | // https://gist.github.com/arcatdmz/8500521 |
8 | // https://gist.github.com/arcatdmz/8500521 |
9 | // - Amazon で使った金額の合計を出す奴 (2014 年バージョン) |
9 | // - Amazon で使った金額の合計を出す奴 (2014 年バージョン) |
10 | // https://gist.github.com/polamjag/866a8af775c44b3c1a6d |
10 | // https://gist.github.com/polamjag/866a8af775c44b3c1a6d |
11 | |
| |
12 | (function(){ |
11 | (function () { |
13 | |
| |
14 | // 各注文履歴をTSVフォーマットにして返す |
12 | // 各注文履歴をTSVフォーマットにして返す |
15 | var datePattern = new RegExp("(\\d{4})年(\\d{1,2})月(\\d{1,2})日"); |
13 | var datePattern = new RegExp("(\\d{4})年(\\d{1,2})月(\\d{1,2})日"); |
16 | function formatEntry(entry) { |
14 | function formatEntry(entry) { |
17 | console.log(entry); |
15 | console.log(entry); |
18 | entry.date.match(datePattern); |
16 | entry.date.match(datePattern); |
19 | var year = RegExp.$1; |
17 | var year = RegExp.$1; |
20 | var month = RegExp.$2; if (month.length <= 1) month = "0" + month; |
18 | var month = RegExp.$2; |
21 | var day = RegExp.$3; if (day.length <= 1) day = "0" + day; |
19 | if (month.length <= 1) |
| |
20 | month = "0" + month; |
| |
21 | var day = RegExp.$3; |
| |
22 | if (day.length <= 1) |
| |
23 | day = "0" + day; |
22 | var date = "" + year + "/" + month + "/" + day; |
24 | var date = "" + year + "/" + month + "/" + day; |
23 | var arr = [date, entry.name, entry.author, entry.url]; |
25 | var arr = [date, entry.name, entry.author, entry.url]; |
24 | return arr.join('\t') + "\n"; |
26 | return arr.join('\t') + "\n"; |
25 | } |
27 | } |
26 | |
| |
27 | function popup(content) { |
28 | function popup(content) { |
28 | var generator=window.open('','name','height=250,width=700'); |
29 | var generator = window.open('', 'name', 'height=250,width=700'); |
29 | generator.document.write('<html><head><title>Amazon to TSV</title>'); |
30 | generator.document.write('<html><head><title>Amazon to TSV</title>'); |
30 | generator.document.write('</head><body>'); |
31 | generator.document.write('</head><body>'); |
31 | generator.document.write('<pre>'); |
32 | generator.document.write('<pre>'); |
32 | generator.document.write(content); |
33 | generator.document.write(content); |
33 | generator.document.write('</pre>'); |
34 | generator.document.write('</pre>'); |
34 | generator.document.write('</body></html>'); |
35 | generator.document.write('</body></html>'); |
35 | generator.document.close(); |
36 | generator.document.close(); |
36 | return generator; |
37 | return generator; |
37 | } |
38 | } |
38 | |
| |
39 | var itemDelimiter = " / "; |
39 | var itemDelimiter = " / "; |
40 | var total = {}; |
40 | var total = {}; |
41 | var year = '2014'; |
41 | var year = '2014'; |
| |
42 | var nyear = 2014; |
42 | var all = false; |
43 | var all = false; |
43 | |
| |
44 | function init(num) { |
44 | function init(num) { |
45 | if(typeof num !== 'number') { |
45 | if (typeof num !== 'number') { |
46 | var num = 0; |
46 | var num = 0; |
47 | $('<div/>').css({ |
47 | $('<div/>').css({ |
48 | position: 'fixed', |
48 | position: 'fixed', |
49 | left: 0, |
49 | left: 0, |
50 | top: 0, |
50 | top: 0, |
51 | width: '100%', |
51 | width: '100%', |
52 | height: '100%', |
52 | height: '100%', |
53 | zIndex: 1000, |
53 | zIndex: 1000, |
54 | backgroundColor: 'rgba(0,0,0,.7)', |
54 | backgroundColor: 'rgba(0,0,0,.7)', |
55 | color: '#fff', |
55 | color: '#fff', |
56 | fontSize: 30, |
56 | fontSize: 30, |
57 | textAlign: 'center', |
57 | textAlign: 'center', |
58 | paddingTop: '15em' |
58 | paddingTop: '15em' |
59 | }).attr('id', '___overlay').text('Amazonいくら使った?').appendTo('body'); |
59 | }).attr('id', '___overlay').text('Amazonいくら使った?').appendTo('body'); |
60 | year = window.prompt('何年分の注文を集計しますか?\n - 半角数字4桁で入力してください\n - 全期間を集計する場合は「all」と入力します', year); |
60 | year = window.prompt('何年分の注文を集計しますか?\n - 半角数字4桁で入力してください\n - 全期間を集計する場合は「all」と入力します', year); |
61 | if(year === 'all') { |
61 | if (year === 'all') { |
62 | all = true; |
62 | all = true; |
63 | year = jQuery('div.top-controls select option:last').val().match(/[0-9]/g).join(''); |
63 | year = jQuery('div.top-controls select option:last').val().match(/[0-9]/g).join(''); |
64 | } else if(!/^[0-9]{4}$/.test(year)) { |
64 | } |
| |
65 | else if (!/^[0-9]{4}$/.test(year)) { |
65 | alert('正しい数値を入力してください'); |
66 | alert('正しい数値を入力してください'); |
66 | $('#___overlay').remove(); |
67 | $('#___overlay').remove(); |
67 | return false; |
68 | return false; |
68 | } |
69 | } |
69 | year = Number(year); |
70 | nyear = Number(year); |
70 | } |
71 | } |
71 | // 第二引数を true にすると各商品とかエラーを逐一表示する |
72 | // 第二引数を true にすると各商品とかエラーを逐一表示する |
72 | var progress = load(num, false); |
73 | var progress = load(num, false); |
73 | $('#___overlay').text(year+'年の集計中… / '+(num+1)+'ページ目'); |
74 | $('#___overlay').text(nyear + '年の集計中… / ' + (num + 1) + 'ページ目'); |
74 | progress.done(function(results){ |
75 | progress.done(function (results) { |
75 | if (typeof total[year] === 'undefined') { |
76 | if (typeof total[nyear] === 'undefined') { |
76 | total[year] = results; |
77 | total[nyear] = results; |
77 | } else { |
78 | } |
78 | total[year] = total[year].concat(results); |
79 | else { |
| |
80 | total[nyear] = total[nyear].concat(results); |
79 | } |
81 | } |
80 | init(num+1); |
82 | init(num + 1); |
81 | }).fail(function(){ |
83 | }).fail(function () { |
82 | if(all && new Date().getFullYear() > year) { |
84 | if (all && new Date().getFullYear() > nyear) { |
83 | year++; |
85 | nyear++; |
84 | init(0); |
86 | init(0); |
85 | } else { |
87 | } |
| |
88 | else { |
86 | var _total = 0; |
89 | var _total = 0; |
87 | var _content = ""; |
90 | var _content = ""; |
88 | jQuery.each(total, function(year, results){ |
91 | jQuery.each(total, function (nyear, results) { |
89 | var yen = 0; |
92 | var yen = 0; |
90 | jQuery.each(results, function(){ |
93 | jQuery.each(results, function () { |
91 | yen += this.price; |
94 | yen += this.price; |
92 | $.each(this.items, function(i, item){ |
95 | $.each(this.items, function (i, item) { |
93 | _content += formatEntry(item); |
96 | _content += formatEntry(item); |
94 | }); |
97 | }); |
95 | }); |
98 | }); |
96 | _total += yen; |
99 | _total += yen; |
97 | }); |
100 | }); |
98 | // result |
101 | // result |
99 | $('#___overlay').remove(); |
102 | $('#___overlay').remove(); |
100 | alert('合計 ' + _total + ' 円'); |
103 | alert('合計 ' + _total + ' 円'); |
101 | popup(_content); |
104 | popup(_content); |
102 | console.log('合計 ' + _total + ' 円'); |
105 | console.log('合計 ' + _total + ' 円'); |
103 | } |
106 | } |
104 | }); |
107 | }); |
105 | } |
108 | } |
106 | |
| |
107 | function load(num, verbose) { |
109 | function load(num, verbose) { |
108 | var df = jQuery.Deferred(); |
110 | var df = jQuery.Deferred(); |
109 | var page = get(num, verbose); |
111 | var page = get(num, verbose); |
110 | page.done(function(data){ |
112 | page.done(function (data) { |
111 | var dom = jQuery.parseHTML(data); |
113 | var dom = jQuery.parseHTML(data); |
112 | var results = []; |
114 | var results = []; |
113 | |
| |
114 | jQuery(dom).find('div.order').each(function(){ |
115 | jQuery(dom).find('div.order').each(function () { |
115 | var box = jQuery(this); |
116 | var box = jQuery(this); |
116 | var dateText = jQuery(box.find('div.order-info span.value')[0]).text().trim(); |
117 | var dateText = jQuery(box.find('div.order-info span.value')[0]).text().trim(); |
117 | |
| |
118 | var items = []; |
118 | var items = []; |
| |
119 | var item = {}; |
119 | var pubarr = box.find("div.a-row > span.a-size-small"); |
120 | var pubarr = box.find("div.a-row > span.a-size-small"); |
120 | box.find("div.a-row > a.a-link-normal").each(function(j) { |
121 | box.find("div.a-row > a.a-link-normal").each(function (j) { |
121 | var item = {}; |
122 | item = {}; |
122 | item.name = $(this).text().trim(); |
123 | item['name'] = $(this).text().trim(); |
123 | item.path = $(this).attr('href').trim(); |
124 | item['path'] = $(this).attr('href').trim(); |
124 | item.url = 'https://www.amazon.co.jp' + item.path; |
125 | item['url'] = 'https://www.amazon.co.jp' + item['path']; |
125 | item.date = dateText; |
126 | item['date'] = dateText; |
126 | item.author = $(pubarr[j*2]).text().trim().replace(/(\n)/g, ''); |
127 | item['author'] = $(pubarr[j * 2]).text().trim().replace(/(\n)/g, ''); |
127 | item.price = $(this).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().find(".order-info").find(".a-span2").find(".a-size-base").find(".value").text().trim(); |
128 | item['price'] = $(this).parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().parent().find(".order-info").find(".a-span2").find(".a-size-base").find(".value").text().trim(); |
128 | items.push(item); |
129 | items.push(item); |
129 | }); |
130 | }); |
130 | |
| |
131 | var priceText = jQuery(box.find('div.order-info span.value')[1]).text(); |
131 | var priceText = jQuery(box.find('div.order-info span.value')[1]).text(); |
132 | var price = Number(priceText.match(/[0-9]/g).join('')); |
132 | var price = Number(priceText.match(/[0-9]/g).join('')); |
133 | |
133 | if (verbose) |
134 | if (verbose) console.log(item, price); |
134 | console.log(item, price); |
135 | results.push({'date':dateText,'items':items,'price':price}); |
135 | results.push({ 'date': dateText, 'items': items, 'price': price }); |
136 | }); |
136 | }); |
137 | |
137 | if (results.length <= 0) |
138 | if(results.length <= 0) df.reject(); |
138 | df.reject(); |
139 | else df.resolve(results); |
139 | else |
| |
140 | df.resolve(results); |
140 | }); |
141 | }); |
141 | return df.promise(); |
142 | return df.promise(); |
142 | } |
143 | } |
143 | |
144 | function get(num, verbose) { |
144 | function get(num) { |
| |
145 | var df = jQuery.Deferred(); |
145 | var df = jQuery.Deferred(); |
146 | jQuery.ajax({ |
146 | jQuery.ajax({ |
147 | url: 'https://www.amazon.co.jp/gp/css/order-history?digitalOrders=1&unifiedOrders=1&orderFilter=year-'+year+'&startIndex='+num*10, |
147 | url: 'https://www.amazon.co.jp/gp/css/order-history?digitalOrders=1&unifiedOrders=1&orderFilter=year-' + year + '&startIndex=' + num * 10, |
148 | beforeSend: function (xhr){ |
148 | beforeSend: function (xhr) { |
149 | xhr.setRequestHeader('X-Requested-With', {toString: function(){ return ''; }}); |
149 | //xhr.setRequestHeader('X-Requested-With', { toString: function () { return ''; } }); |
| |
150 | function toString() { return ''; } |
| |
151 | xhr.setRequestHeader('X-Requested-With', 'toString'); |
| |
152 | //xhr.setRequestHeader('X-Requested-With', '');//NG |
150 | }, |
153 | }, |
151 | }) |
154 | success: function (data) { |
152 | .success(function(data){ |
| |
153 | df.resolve(data); |
155 | df.resolve(data); |
| |
156 | } |
154 | }) |
157 | }) |
155 | .fail(function(jqXHR, msg){ |
158 | .fail(function (jqXHR, msg) { |
156 | if (verbose) console.log("fail", msg); |
159 | if (verbose) |
| |
160 | console.log("fail", msg); |
157 | }); |
161 | }); |
158 | return df.promise(); |
162 | return df.promise(); |
159 | } |
163 | } |
160 | |
| |
161 | if(typeof jQuery !== 'function') { |
164 | if (typeof jQuery !== 'function') { |
162 | var d=document; |
165 | var d = document; |
163 | var s=d.createElement('script'); |
166 | var s = d.createElement('script'); |
164 | s.src='//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'; |
167 | s.src = '//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js'; |
165 | s.onload=init; |
168 | s.onload = function (e) { init(null); }; |
166 | d.body.appendChild(s); |
169 | d.body.appendChild(s); |
167 | } else { |
| |
168 | init(); |
| |
169 | } |
170 | } |
170 | })(); |
171 | else { |
| |
172 | init(null); |
| |
173 | } |
| |
174 | })(); |
| |
175 | //# sourceMappingURL=amazon_record.js.map |