今まで投稿したQiita記事を振り返りたい

## 目次
* [概要](#概要)
* [構成](#構成)
* [実装内容](#実装内容)
* [実行結果](#実行結果)
* [今後](#今後)
* [参考資料](#参考資料)

## 概要
Qiitaを始めて1年ぐらいたったので、今まで書いた記事を振り返ろうと思ったが、今だと情報が少ないので細かい振り返りは断念した。
なので、今年から記事の閲覧数等を日や月単位で取れるようにGASを書いておいて、
また来年振り返るまでの準備をした（もしくは準備中）の話になります。
※GASは一旦日次で動かそうと思います。

#### とはいえ今できる振り返り
今までの記事(総数6件)の閲覧数の平均は1500~2000の間ぐらいで、いいね数とストック数の平均も1と多くなかった。
いいね数が0だけど閲覧数が3200ぐらいの記事があり、それが閲覧数トップだったのが意外でした。

改善点を[LAPRAS](https://lapras.com/)のAIReviewで確認したところ、もっと説明を追記する必要がありそう。
確かに画面キャプチャとリンクが多かったかなと思うので、次回からもう少し自分の説明を追加しようと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/53350440-cee3-cd8c-9952-f35af7792520.png)


## 構成
スプレッドシートには以下の項目を記録していく。
スプレッドシートで耐えられなさそうなら、無料で使えるDB的なものがないか探してみようと思います。

| 項目名 | 型 | 入力元 | 備考 |
|:-|:-|:-|:-|
| id  |  String | QiitaAPI  |  Qiitaで振られている記事のid |
| title  |  String | QiitaAPI  |  記事のタイトル |
| url  |  String | QiitaAPI  |  記事のURL |
| likes_count  | Number  | QiitaAPI  |  記事へのいいね数 |
| reactions_count  | Number  | QiitaAPI  |  記事へのリアクション数 |
| stocks_count  | Number  | QiitaAPI  | 記事のストック数  |
| page_views_count  | Number  |  QiitaAPI | 記事の閲覧数  |
| tag_0  | String  |  QiitaAPI | 記事につけたタグ  |
| tag_1  | String  |  QiitaAPI | 記事につけたタグ  |
| tag_2  | String  |  QiitaAPI | 記事につけたタグ  |
| tag_3  | String  |  QiitaAPI | 記事につけたタグ  |
| tag_4  | String  |  QiitaAPI | 記事につけたタグ  |
| posted_at  | Date  | QiitaAPI  | 記事の投稿日時  |
| created_by  | String  | GAS  | レコード登録者  |
| created_at  | Date  | GAS  | レコード登録日時  |
| updated_by  | String  | GAS  | レコード更新者  |
| updated_at  | Date  | GAS  | レコード更新日時  |

## 実装内容
認証中アカウントの記事をAPIで取得して、スプレッドシートに書き出しています。
APIのアクセストークンやリトライ最大回数等は、スクリプトプロパティで管理しています。
これを日次で動かすことで、閲覧数を日単位や週単位で取れるようになることを期待しています。

* GASの内容
```javascript
function main() {
  const qiitaClient = new QiitaClient();
  const items = qiitaClient.getItems();
  const sheet = new Sheet();
  sheet.appendItems(items);
}

const UPDATED_BY = "system";

const Property = {
  QIITA_GET_ITEMS_URL: PropertiesService.getScriptProperties().getProperty("QIITA_GET_ITEMS_URL"),
  QIITA_API_MAX_RETRY_COUNT: PropertiesService.getScriptProperties().getProperty("QIITA_API_MAX_RETRY_COUNT"),
  QIITA_ACCESS_TOKEN: PropertiesService.getScriptProperties().getProperty("QIITA_ACCESS_TOKEN"),
  QIITA_API_RETRY_DURATION: PropertiesService.getScriptProperties().getProperty("QIITA_API_RETRY_DURATION"),
}

const APIClientMessage = {
  QiitaAPIRetry: 'QiitaAPIの呼び出しをリトライします。 %d回目',
  QiitaAPIError: 'QiitaAPIの呼び出しに失敗しました。'
}

class QiitaClient {

  getItems() {
    const options = {
      'headers': {
        'Authorization': `Bearer ${Property.QIITA_ACCESS_TOKEN}`
      }
    };

    let retryCount = 0;
    let result = null;
    do {
      try {
        const response = UrlFetchApp.fetch(Property.QIITA_GET_ITEMS_URL, options);
        result = JSON.parse(response.getContentText());
      } catch (e) {
        console.error(e);
        Utilities.sleep(Property.QIITA_API_RETRY_DURATION);
        retryCount++;
        console.warn(APIClientMessage.QiitaAPIRetry, retryCount);
        continue; 
      }
    } while (retryCount < Property.QIITA_API_MAX_RETRY_COUNT && result === null);

    if (result === null) {
      throw new Error(APIClientMessage.QiitaAPIError);
    }    
    return result;
  }
}

class Sheet {

  constructor(spreadsheet = SpreadsheetApp.getActiveSpreadsheet(), sheet = spreadsheet.getSheetByName("item_count_history"), headerRows = 1, headerIndex = 0) {
    /** @type {SpreadsheetApp.Spreadsheet} */
    this.spreadsheet = spreadsheet;
    /** @type {SpreadsheetApp.Sheet} */
    this.sheet = sheet;
    /** @type {number} */
    this.headerRows = headerRows;
    /** @type {number} */
    this.headerIndex = headerIndex;
  }

  appendItems(items) {
    const now = new Date();
    items.forEach(item => {
      this.sheet.appendRow([
        item["id"],
        item["title"], 
        item["url"], 
        item["likes_count"], 
        item["reactions_count"], 
        item["stocks_count"], 
        item["page_views_count"],
        item["tags"][0]?.name,
        item["tags"][1]?.name,
        item["tags"][2]?.name,
        item["tags"][3]?.name,
        item["tags"][4]?.name,
        item["created_at"],
        UPDATED_BY,
        now,
        UPDATED_BY,
        now
      ]);
    });
  }
}
```

* トリガーの設定
毎朝7時ぐらいに動かすようにしています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/2aef7acf-eac7-afad-6e06-035b7ea37d2b.png)


## 実行結果
トリガーで実行した場合
* GASの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/eed7b094-f9ca-9b2a-43b2-7832a345dc77.png)

* スプレッドシート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/b72175a9-bd4f-0bca-2b1c-bc45a8442cd8.png)

直で実行した場合
* GASの画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/e4ad62d7-eded-de79-adf9-230425b9a813.png)

* スプレッドシート
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/534209/796e5710-1c6d-e17c-d800-ff26cc86d714.png)

## 今後
上記GASで蓄積された情報をもとに スプレッドシート or **無料**のBIツールで集計を行い、
今後に生かせればと思っています。

## 参考
https://qiita.com/api/v2/docs
https://dev.classmethod.jp/articles/google-apps-script-request/