家計簿を一括ダウンロード,その2

FireFoxのコンソールで実行すると,ページをパースして,管理IDごとCSVに保存。

MoneyforwardのWeb上でカテゴリを変更するのが面倒だから,
Excelで編集して反映したいけど,CSVのアップロードではできない。
なので,一括変更のScriptを作成中。
とりあえず,管理IDがダウンロードできたから,
次はアップデートの方かな。


var downloadAsTextFile = function(fileName, content) {
    var a = document.createElement('a');
    a.download = fileName;
    a.href = (window.URL || window.webkitURL).createObjectURL(new Blob([new Uint8Array([0xEF, 0xBB, 0xBF]), content]));
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
};

var downloadAsCSVFile = function(fileName, rows) {
  var content = "";
  for(var i in rows) {
    for (var j = 0, m = rows[i].length; j < m; ++j) content += '"' + ("" + rows[i][j]).replace(/"/g, '""') + '"' + (j !== m ? ',' : '');
    content += '\n';
  }
  downloadAsTextFile(fileName, content);
};

var parseListBody = function(text, rows) {
  var dom = eval("$" + text.match(/list_body.*?(\(.*)/)[1]); 
  
  $(dom.filter("tr").get().reverse()).each((i, tr) => {
    /*
    $("td", tr).each((j, td) => {
      rows.push(["tbl", i, j, td.className, $(td).text().trim(), $(td).prop('outerHTML').replace(/[\n\r]/g,"").trim()]);
    });
    */
    
    //var form        = $("form", tr).serializeArray();
    var id            = $("input[name*='\[id\]']", tr).val();
    var lctg_id       = $("input[name*='\[large_category_id\]']", tr).val();
    var mctg_id       = $("input[name*='\[middle_category_id\]']", tr).val();
    var hash          = $("input[name*='\[sub_account_id_hash\]']", tr).val();
    var income        = $("input[name*='\[is_income\]']", tr).val();
    var target        = $("input[name*='\[is_target\]']", tr).val()||"";
    var td_date       = $("td.date", tr); 
    var date_id       = td_date.attr("data-table-sortable-value");
    var date_str      = td_date.text().trim();
    var content       = $("td.content div span", tr).text().trim();
    var amount        = $("td.amount span.offset, td.amount div.noform", tr).text().trim();
    var amount_memo   = $("td.amount div.offset", tr).text().trim();
    var pull_right    = $("td.amount div.pull-right", tr).text().trim();
    var note          = $("td.note, td.sub_account_id_hash span", tr).text().trim();
    var explain       = $("td.calc[title]", tr).attr("title");
    var transfer_from = $($("td.calc div.transfer_account_box", tr).parent().prop('outerHTML')).children().empty().parent().text().trim();
    var transfer_to   = $("td.calc div.transfer_account_box", tr).text().trim();
    var lctg          = $("td.lctg", tr).text().trim();
    var mctg          = $("td.mctg", tr).text().trim();
    var memo          = $("td.memo", tr).text().trim();
    
    rows.push([id, income, target, date_id.substr(0, 10), date_id, date_str, content, amount, amount_memo, pull_right, note, transfer_from, transfer_to, explain, lctg_id, lctg, mctg_id, mctg, memo, hash]);
    //rows.push([]);
  });
};

var Queue = function() {
  this.promise = Promise.resolve(true);
  this.addAsync = (action) => this.promise = this.promise.then(() => new Promise((resolve) => action(resolve)));
  this.addSync  = (action) => this.addAsync((resolve) => { action(); resolve(); });
  this.delay    = (delay)  => this.addAsync((resolve) => setTimeout(resolve, delay));
};

var getList = (q, rows, year, month) => {
  q.addAsync((resolve) => {
    $.ajax({
      dataType: "text",
      type:     "POST", 
      url:      "https://moneyforward.com/cf/fetch",
      data: {
        account_id_hash: "",
        from:            year + "/" + month + "/1",
        service_id:      ""
      },
      headers: {
        "X-CSRF-Token": $("meta[name=csrf-token]").attr("content")
      }
    }).done((text) => { console.log(year + "/" + month + "/1"); parseListBody(text, rows); resolve(); });
  });
};


var q = new Queue();
var rows = [["id", "income", "target", "date", "date_id", "date_str", "content", "amount", "amount_memo", "pull_right", "note", "transfer_from", "transfer_to", "explain", "lctg_id", "lctg", "mctg_id", "mctg", "memo", "hash"]];

for(var y = 2010; y <= 2018; ++y) {
  for(var m = 1; m <= 12; ++m) {
    getList(q, rows, y, m);
  }
}

q.addSync(() => downloadAsCSVFile("hoge.csv", rows));
q.addSync(() => alert("完了"));

  (()=>{
    var Queue = function() {
      this.promise = Promise.resolve(true);
      this.addAsync = (action) => this.promise = this.promise.then(() => new Promise((resolve) => action(resolve)));
      this.addSync  = (action) => this.addAsync((resolve) => { action(); resolve(); });
      this.delay    = (delay)  => this.addAsync((resolve) => setTimeout(resolve, delay));
    };

    var q = new Queue();
    var jqxhr, jqxhr2;
    var sub_win_option = "top=0,left=0,width=500,height=500,scrollbars=1,location=0,menubar=0,toolbar=0,status=1,directories=0,resizable=1";
    var sv_win = window.open(window.location, "show_view_window", sub_win_option);
    $(sv_win.document).ready(() => {
      var w   = $(window);
      var st  = w.scrollTop(), sb = st + w.height();
      
      var sub;
      q.delay(2000);
      q.addSync(() => { sub = $(sv_win.document.body); sub.empty(); });
      
      $('a._work, a.gtm-thumbnail-link').each((i,v) => {
        var a = $(v);
        var t = a.offset().top;
        if(st < t && t < sb)
        {
          var href = a.attr('href');
          var is_manga = $('.page-count, ._1VJYUl1', a ).length > 0;
          var fetch_manga = (resolve) => {
            var url = href.replace(/mode=medium/, "mode=manga");
            console.log("fetch_manga", url);
            if(jqxhr2)
            {
              jqxhr2.abort();
            }
            jqxhr2 = $.ajax({ url: url }).done( (data) => {
              $('section.manga img', data).each((i, e) => {
                $('<img/>').attr("src", $(e, data).attr('data-src')).css({ "max-width": "-moz-available" }).appendTo(sub);
              });
              resolve();
            }).fail((jqXHR, textStatus, errorThrown) => {
              console.log('fail', jqXHR.status);
              resolve();
            });
          };
          
          var fetch_image = (resolve) => {
            console.log("fetch_image", href);
            if(jqxhr)
            {
              jqxhr.abort();
            }
            
            jqxhr = $.ajax({ url: href }).done( (data) => {
              var img = $("img.original-image", data);
              if(img.length > 0) {
                $('<img/>').attr("src", img.attr('data-src')).css({ "max-width": "-moz-available" }).appendTo(sub);
                resolve();
              } else {
                fetch_manga(resolve);
              }
            });
          };
          
          q.addAsync((resolve) => {
            //console.log(is_manga, href);
            if( is_manga )
            {
              fetch_manga(resolve);
            } else {
              fetch_image(resolve);
            }
          });
        }
      });
    });
  })();