#作るに至った経緯
会計処理の際に購入予定のもの情報を一つ一つExcelにコピーして貼り付ける作業が毎回手作業なので、どうにか時間短縮できないかなと思い、自動化するスクリプトを作ることにしました。NodeやSeleniumだと既存のブラウザにアタッチできないのでjavascriptを使いました。
#今回やったこと
モノタロウの通販サイトにログインし、カートに入っている全ての商品の情報をCSVファイルに自動でまとめてくれるスクリプトを作りました。
ちなみに秋月電子は
https://tlt.gurigoro.net/entry/2018/01/13/200510 この拡張機能を使ってまとめるとよいです。
できるだけ有りものは利用しましょう。
#環境
Windows10 Home
CPU: Intel Core i5 7200U
tampermonkey
javascript
Google Chrome
#本題
##前提
モノタロウの通販サイトで既に買いたい商品がカートに入っていて、ログインが済んでいる。カートのページにいる。
##プログラムの流れ
モノタロウの商品カートから情報を取得
取得した情報の配列を作る
配列の整形
配列からCSVに変換する
CSVファイルをダウンロードする
##ブラウザでCSVをダウンロードする方法
Google chrome上のjavascriptでCSVファイルをダウンロードする方法を学びました。まずはこちらのサイトを参考に情報を取得した前提でCSVをダウンロードしてみます。ちなみにこのCSVファイルはwindowsでないと文字化けします。詳しくはjavascript で作成したCSVファイルをエクセルで表示可能にするを参考にしてください。
##tampermonkeyの導入
まずはchrome拡張 tampermonkeyを入れます。登録したページに行くとjavascriptを実行してくれる拡張機能です。
詳細はこちらの記事が参考になります。
##カートの中身の情報をスクレイピングする
tampermonkeyという拡張機能を使って製品名などの情報を取得し、csvに出力します。残念ながら今の私の技能ではtampermonkeyとspredsheetを連携させることは無理でした。
要素の取得はCSSセレクタを手打ちで入力していきました。コーディングのポイントは、そのタグやクラスの名前が固有のものだったらそのまま書く、固有でなかったら子要素を利用して絞り込みます。item_content
など、親要素の名前が同じ場合がありますが、子要素のクラス名が独特なものなので直接指定しています。入れ子にするかは状況をみて使い分けましょう。
tampermonkeyでは(function() {})()
の{}
の中にコードを書いて実行します。
・@matchは実行するページのURLを書きます。ここに書いたページに遷移すると実行されるので、カートに入るボタンを押したら実行されることになります。
// ==UserScript==
// @name カートの中身CSV出力くん
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://www.monotaro.com/monotaroMain.py?func=monotaro.basket.showListServlet.ShowListServlet&RtnPage=%2Fg%2F04470570%2F%3Fes%3D1
// @grant none
// ==/UserScript==
(function() {
let product_name = [];
let oneset_num = [];
let price = [];
let buy_num = [];
let url = [];
let subtotal = [];
const Store = 'モノタロウ';
let heder_label = ['用途', '種別', '製品名', '購入場所', '内容量', '単価', '購入数量', 'URL', '小計', '合計'];
const ProductInfo = () => {
let elm = document.querySelectorAll('.product_td');//商品ブロックの要素を取得
let price_elm = document.querySelectorAll('td.price_td');//金額ブロックの要素を取得
for (let i = 0; i < elm.length; i++) {
product_name[i] = elm[i].querySelector('h4>a').innerText;//製品名を取得
//oneset_num[i] = elm[i].querySelector('li>#text').innerText;//内容量を取得
url[i] = elm[i].querySelector('h4>a').href;//urlを取得
}
for (let i = 0; i < price_elm.length; i++) {
price[i] = price_elm[i].querySelector('td.item_content').innerText;//値段
buy_num[i] = price_elm[i].querySelector('input.button_items_quantity.imemode_inactive').value;//購入数量
subtotal[i] = price_elm[i].querySelector('em').innerText;//小計
}
}
class CSV {
constructor(data, keys = false) {
this.ARRAY = Symbol('ARRAY');
this.OBJECT = Symbol('OBJECT');
this.data = data;
if (CSV.isArray(data)) {
if (0 == data.length) {
this.dataType = this.ARRAY
} else if (CSV.isObject(data[0])) {
this.dataType = this.OBJECT
} else if (CSV.isArray(data[0])) {
this.dataType = this.ARRAY
} else {
throw Error('Error: 未対応のデータ型です')
}
} else {
throw Error('Error: 未対応のデータ型です')
}
this.keys = keys
}
toString() {
if (this.dataType === this.ARRAY) {
return this.data.map((record) => (
record.map((field) => (
CSV.prepare(field)
)).join(',')
)).join('\n')
} else if (this.dataType === this.OBJECT) {
const keys = this.keys || Array.from(this.extractKeys(this.data))
const arrayData = this.data.map((record) => (
keys.map((key) => record[key])
))
console.log([].concat([keys], arrayData))
return [].concat([keys], arrayData).map((record) => (
record.map((field) => (
CSV.prepare(field)
)).join(',')
)).join('\n')
}
}
save(filename = 'data.csv') {
if (!filename.match(/\.csv$/i)) { filename = filename + '.csv' }
console.info('filename:', filename);
console.table(this.data);
const csvStr = this.toString();
const bom = new Uint8Array([0xEF, 0xBB, 0xBF]);
const blob = new Blob([bom, csvStr], { 'type': 'text/csv' });
const url = window.URL || window.webkitURL;
const blobURL = url.createObjectURL(blob);
let a = document.createElement('a');
a.download = decodeURI(filename);
a.href = blobURL;
a.type = 'text/csv';
a.click();
}
extractKeys(data) {
return new Set([].concat(...this.data.map((record) => Object.keys(record))));
}
static prepare(field) {
return '"' + ('' + field).replace(/"/g, '""') + '"';
}
static isObject(obj) {
return '[object Object]' === Object.prototype.toString.call(obj);
}
static isArray(obj) {
return '[object Array]' === Object.prototype.toString.call(obj);
}
}
const MakeList = () => {
let csvfile = [heder_label,];
for (let i = 0; i < product_name.length; i++) {
csvfile.push([, , product_name[i], Store, oneset_num[i], price[i], buy_num[i], url[i], subtotal[i]]);
}
return csvfile;
}
//console.log(MakeList());
ProductInfo();
(new CSV(MakeList())).save('buylist.csv');//csvオブジェクトの作成 引数にはファイル名を指定
})();
新しいスクリプトをtampermonkeyに書いて有効にしたらモノタロウのカートに移動します。すると、以下のようなテーブルでcsvファイルが作成され、CSVファイルがダウンロードできます。
#最後に
seleniumだと環境構築が面倒ですが、tampermonkeyは拡張機能のインストールだけで動くので非常に簡単でいいですね。
今回でjavascriptを使ったスクレイピングはできるようになったので、今後は別のECサイトの分もつくりたいです。
参考
https://qiita.com/sagami1991/items/794168cf14ed198d6372
https://blog.mudatobunka.org/entry/2017/04/23/135753