Amazonの注文履歴ページから商品のASINコードを取得する雑JavaScript

これを参考にした

- Amazonで一年間に使った金額と、注文履歴のTSVを出力するブックマークレット【2015年版】  
https://qiita.com/koyopro/items/d8b259f1eb75a01d3a0b
- koyopro/amazon-calc.js  
https://gist.github.com/koyopro/a480a45712ccf1bf239c


下記スクリプトを、注文履歴ページ上で対象期間を絞った上で実行すると、商品名・ASINコード・商品ページURLが記載されたcsvが吐き出される。

<img width="1680" alt="スクリーンショット 2019-12-18 20.54.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553450/a2a3eb81-aa22-2cc0-e559-fd9e0894c6f3.png">

<img width="1680" alt="スクリーンショット 2019-12-18 20.55.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553450/1acd7a5b-62f8-738a-b28e-9e10e22aee76.png">

<img width="1680" alt="スクリーンショット 2019-12-18 20.56.13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/553450/55a6c53d-e07b-efcd-5099-36a249b72502.png">



**スクリプト**

```javascript
// メッセージ用オーバーレイ初期化
var overlayId = 'overlay';
function initMsgOverlay() {
  var overlay = document.createElement('div');
  overlay.id = overlayId;
  overlay.style.position = 'fixed';
  overlay.style.left = 0;
  overlay.style.top = 0;
  overlay.style.width = '100%';
  overlay.style.height = '100%';
  overlay.style.zIndex = 100;
  overlay.style.backgroundColor = 'rgba(0,0,0,0.7)';
  overlay.style.color = '#fff';
  overlay.style.textAlign = 'center';
  overlay.style.paddingTop = '15em';
  document.body.appendChild(overlay);
}
function displayMsg(msg) {
  document.getElementById(overlayId).innerHTML = '<h1>' + msg + '</h1>';
}
function appendMsg(msg) {
  document.getElementById(overlayId).innerHTML += '<h1>' + msg + '</h1>';
}
function appendMsgSmall(msg) {
  document.getElementById(overlayId).innerHTML += '<br><h3>' + msg + '</h3>';
}

function getTargetPeriod() {
  try {
    var period = document.querySelector('#timePeriodForm .a-dropdown-prompt').textContent.trim();
    return period
  } catch(error) {
    displayMsg('対象期間を取得できません')
    throw Error
  }
}

function generateCsv(itemDetails) {
  var header = '"商品名","ASIN","商品ページURL"\n';
  var body = '';
  for (var i=0; i<itemDetails.length; i++) {
    body += '"' + itemDetails[i]['name'].replace(/"/g, '""') + '",';
    body += '"' + itemDetails[i]['asin'].replace(/"/g, '""') + '",';
    body += '"' + itemDetails[i]['url'].replace(/"/g, '""') + '"\n'
  }
  return header + body;
}


function sleep(milliSec) {
  return new Promise(resolve => {
    setTimeout(resolve, milliSec);
  });
}

async function getItemDetails(orderHistoryHtml, itemDetails) {
  return new Promise(async (resolve, reject) => {
    var itemNameSelector = '.a-box-group.a-spacing-base.order .a-fixed-left-grid-col.a-col-right div.a-row > a.a-link-normal';
    var itemNameElements = Array.from(orderHistoryHtml.querySelectorAll(itemNameSelector));
    var itemNames = itemNameElements.map(elem => elem.textContent.trim());
    var itemUrls = itemNameElements.map(elem => elem.href);
    var asinPattern = /gp\/product\/(.*)\/ref=ppx_yo_dt/;
    var itemAsins = itemUrls.map(url => url.match(asinPattern)[1]);

    for (var i=0; i<itemNames.length; i++) {
      var itemDetail = {};
      itemDetail['name'] = itemNames[i];
      itemDetail['asin'] = itemAsins[i];
      itemDetail['url'] = itemUrls[i];
      itemDetails.push(itemDetail);
    }

    var nextPageLinkSelector = '.a-last a';
    var nextPageLinkElement = orderHistoryHtml.querySelector(nextPageLinkSelector);
    var nextPageUrl;
    if (nextPageLinkElement === null) {
      displayMsg('全ページ取得完了');
      console.log('全ページ取得完了');
      resolve();
      return;
    } else {
      nextPageUrl = nextPageLinkElement.href;
      displayMsg('以下のページの情報を取得');
      appendMsg(nextPageUrl);
      console.log('以下のページの情報を取得');
      console.log(nextPageUrl);
      console.log(new Date());
    }

    var request = new XMLHttpRequest();
    request.open('GET', nextPageUrl, false);
    request.send(null);

    if (request.status === 200) {
      var nextPageHtmlText = request.responseText;
      nextPageHtml = document.createElement('div')
      nextPageHtml.innerHTML = nextPageHtmlText;
    }
    await sleep(1500);
    await getItemDetails(nextPageHtml, itemDetails);
    resolve();
  });
}

async function main(itemDetails) {
  initMsgOverlay();
  var period = getTargetPeriod();
  displayMsg(period+'注文のASINコードを取得します');
  await sleep(2000);
  displayMsg('以下のページの情報を取得');
  appendMsg(location.href);
  await getItemDetails(document, itemDetails);
  var csv = generateCsv(itemDetails);
  // csvの内容に"#"があるとdata urlにcsvの内容を設定した際に途中で途切れてしまう
  csv = csv.replace(/#/, '');
  var csvWindow = window.open('', 'csv', 'width=640,height=480');
  
  var downloadLink = csvWindow.document.createElement('a');
  downloadLink.setAttribute('download', 'asin.csv');
  downloadLink.setAttribute('href', 'data:text/html;charset=utf-8,'+csv);
  downloadLink.innerHTML = 'CSVダウンロード';
  
  csvWindow.document.write('<title>取得結果CSV</title>');
  csvWindow.document.write('<p>'+downloadLink.outerHTML+'</p>');
  csvWindow.document.write('<code>');
  csvWindow.document.write(csv);
  csvWindow.document.write('</code>');
}

var itemDetails = [];
main(itemDetails);
```