圏9研究所 工作室

圏9研究所の開発情報資料など

圏9微博Webスクレイピング~微博フォロアー数を解析する part03

今回は、はてなブログ記事へのフォロアー数チャート描画

1.ストーリー
 描画、データとともにはてなブログ内に置く
 はてなプログにアップしたページにjavascriptを埋め込んでチャートを描画する
 データは、csvファイルデータを下書きページに埋め込んで描画ページから読み込む
 下書きページのデータを更新してチャートページを開けば最新データで描画される
2.下書きファイル読込
1)csvファイルのアップロード 詳細step04による
 区切り文字 "-" になるように加工してアップロードする

2)ファイル読込
(1)URL
 下書きプレビュー共有URLを使う

(2)読込
 XMLHttpRequest で読み込む
 Promise でチャート描画と同期させる

3.csvデータの抽出
1)読み込んだ下書き内のデータ所在と書式

<div class="entry-content">\n  \n    <p>-2019/10/19 11:41:11,1031874-2019/10/19 11:56:19,1031881-2019/10/19 11:57:38,1031881-2019/10/19 12:04:52,1031888-</p>\n<p>\xc2\xa0</p>\n    \n\n  \n</div>

2)csv抽出手順 javascript

  //
  //  convertCSVtoArray() 読み込んだCSVデータを二次元配列に変換
  function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される
    var start_entry = str.indexOf( 'entry-content' ); // entry-content 文字位置を探す
    var end_entry = str.indexOf('div',start_entry);   // その後のdiv文字位置を探す
    var str_raw = str.substr(start_entry,end_entry-start_entry+1);    // entry-contentを抜き出す
    var str_a = str_raw.split(/[-]/);    // - を区切り文字として分割する
    // 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成
    var n=0;    // 有効なデータ数
    for(var i=0;i<str_a.length;++i) {
      if(str_a[i].substr(0,2)=='20')  {   // 文字列先頭が 20 なら有効判定
        result[n++] = str_a[i].split(',');  // 区切り文字 , で2分割
      }
    }
  }

4.チャート描画
1)ライブラリの選定
 Chart.js にする(見た目で決定)

2)描画
 描画領域のためのcanvasタグは、scriptの中に入れて保護する
 【注意】scriptの外に置くとサーバに消される
 ファイル読み込み、データ抽出が完了したらPromiseのresponseを返す
 データとチャート書式を整えて描画する

5.はてなブログに書き込むチャート描画コード

  <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
  <script>
  //  canvas設定 【注意】script内に記載すること
  document.write("<div class='chart-container' style='position: relative; height:100%; width:100%'>");
  document.write("<canvas id='myLineChart'></canvas>");
  document.write("</div>");
  //
  //  変数設定
  var result = [];    // 日時,fans 二次元配列を入れるための配列
  //
  //  関数
  //    Chart.js 描画
  function drawChart()  {
    var ctx = document.getElementById('myLineChart');   // chart 本体
    var dt = [];    // datetime
    var fans = [];  // fans

    for(var i = 0; i < result.length; i++) {  // データ構築
      dt[i] = result[i][0];  // datetime
      fans[i] = result[i][1];
    }
    //  chart設定
    var data = {
      labels: dt,
      datasets: [{
        label: 'fans',
        data: fans,
        borderColor: 'rgba(255, 0, 30, 1)',
        lineTension: 0,
        fill: false,  // 塗りつぶさない
        borderWidth: 3
      }]
    };
    var options = {
      title: {
        display: true,
        text: '圏9微博フォロアー数'
      },
      legend: {position: 'bottom'},
      scales: {
        xAxes: [{   // format指定
          type: "time",
          time: {
            unit: 'day',
            displayFormats: {day: "YYYY/MM/DD"}
          },
          display: true,
          scaleLabel: {display: true, labelString: 'Date Time'}
        }],
        yAxes: [{   // 3桁コンマ区切り
          ticks: {
            callback: function(label, index, labels) {
              return label.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
            }
          }
        }]
      }
    };
    var myLineChart = new Chart(ctx, {
      type: 'line',
      data: data,
      options: options
    });
  }
  //    getCSV()  CSVファイルを読み込む Promiseで同期
  //    csvデータを貼り付けた下書きページのURLから読み込む
  function getCSV(url){
    // Return a new promise.
    return new Promise(function(resolve, reject) {
      var req = new XMLHttpRequest(); // HTTPでファイルを読み込むためのXMLHttpRrequestオブジェクトを生成
      // csvデータを貼り付けた下書きページのURLから読み込む
      req.open("get", url, true);
      req.send(null); // HTTPリクエストの発行
      // レスポンスが返ってきたらconvertCSVtoArray()を呼ぶ
      req.onload = function(){
        convertCSVtoArray(req.responseText); // 渡されるのは読み込んだCSVデータ
        resolve(req.response);  // rejectは未実装
      }
    });
  }
  //
  //  convertCSVtoArray() 読み込んだCSVデータを二次元配列に変換
  function convertCSVtoArray(str){ // 読み込んだCSVデータが文字列として渡される
    var start_entry = str.indexOf( 'entry-content' ); // entry-content 文字位置を探す
    var end_entry = str.indexOf('div',start_entry);   // その後のdiv文字位置を探す
    var str_raw = str.substr(start_entry,end_entry-start_entry+1);    // entry-contentを抜き出す
    var str_a = str_raw.split(/[-]/);    // - を区切り文字として分割する
    // 各行ごとにカンマで区切った文字列を要素とした二次元配列を生成
    var n=0;    // 有効なデータ数
    for(var i=0;i<str_a.length;++i) {
      if(str_a[i].substr(0,2)=='20')  {   // 文字列先頭が 20 なら有効判定
        result[n++] = str_a[i].split(',');  // 区切り文字 , で2分割
      }
    }
  }
  //
  //  START
  getCSV("https://luke24e-hb.hatenablog.com/draft/Zn3TPhKGLqvVk-rm3ODmHUsa7Z0")
  .then(function(response) {  // promise 完了処理
    drawChart();    // グラフを描画する為のコールバック関数を指定
  });
</script>

完成したチャート
luke24e-hb.hatenablog.com

part04へ続く