20190724のNode.jsに関する記事は7件です。

[LINE BOT]スムージーに合うプロテインを教えてくれるLINE BOTを作った

目次

  • はじめに
  • 「スムージーチェッカー」の概念図
  • 実際に作ってみた
  • QRコード
  • 感想
  • 参考にしたサイト

はじめに

前回の記事から一か月…
ようやく、作りたいモノが形になりました。
なので、忘備録も兼ねて公開します。

さて、健康寿命を延ばそうと健康志向な世の中になっております。
では、どうやって健康寿命を延ばせるのだろうか…
それは、筋トレです。筋トレをすれば、健康寿命が爆発的に延びます。
ですが、筋トレだけで本当に大丈夫?と思う方も居られるでしょう。
そこでスムージーです。スムージーはすべてを解決してくれる。
そんなこんなで、スムージーに合うプロテインを教えてくれるLINE BOTを作りました。
名前は「スムージーチェッカー」です。
なお、当記よって当記事は筋肉初心者向けです。安心して筋トレに活かしてください!

「スムージーチェッカー」の概念図

b962897a1ffd9c6f50bfe98a32a2993d.png
こんな感じ。

実際に作ってみた

●開発環境
Node.js v10.16.0
npm v6.9.0
Windows10 pro

●コード

sumotheee.js
'use strict';

// LINE BOT用定数
const lineAccessToken = 'LINE BOT チャネルアクセストークン';
const lineSecret = 'LINE BOT シークレットトークン';
const express = require('express'); // 素晴らしいWebアプリケーションフレームワーク
const line = require('@line/bot-sdk'); // LINE Messaging API を使えるようにするソフトウェア開発キット = みんなが使えるパッケージみたいな存在
const PORT = process.env.PORT || 3000;
const config = {
    channelSecret: lineSecret,
    channelAccessToken: lineAccessToken
};
const userID = 'LINE BOT のユーザーID';
// Aiメーカー用定数(ご自由にお使いください)
const aimakerClient = require('request');
const aimakerModelId = 3605; // AIメーカーで作成したAIモデルのIDを指定
const aimakerApiKey = 'c28f3694803e7631c5feb0831f29be77d78cfbbf0b16c001f6e1078f41d8b27be283434fbffe0ee45d83adbbcbb57c5f'; // AIメーカーで作成したAIモデルのAPIキーを指定
// 返信用定数
const greenAdvice = 'ホエイプロテインを加えると、筋肉にも効く素晴らしいスムージーになってGoodだ!';
const healthyAdvice = 'ソイプロテインやバナナ、小松菜などを加えると味もよくなってGoodだ!';
const dessertAdvice = 'こういうのもたまにはいいが、プロテインを飲もう!もしくは加えよう!';
const restartMessage = 'すまない。もう一度、やり直してくれ!';
const proteinImportant = '言うまでもないが、規則正しい生活を心掛けよう!健全な魂は健康な筋肉に宿る!';

const app = express();
app.post('/webhook', line.middleware(config), (req, res) =>
{
    Promise
        .all(req.body.events.map(handleEvent))
        .then((result) => res.json(result));
});

const client = new line.Client(config);

function handleEvent(event)
{
    if (event.type !== 'message' || event.message.type !== 'image')
    {
        return Promise.resolve(null);
    };

    const getImageOptions = {
        url: `https://api.line.me/v2/bot/message/${event.message.id}/content`,
        method: 'get',
        headers: {
            'Authorization': 'Bearer ' + lineAccessToken,
        },
        encoding: null
    };

    let resultMessage = '';
    resultMessage = 'お待ちくださいマッスル';
    aimakerClient(getImageOptions, function (error, response, body)
    {
        if (!error && response.statusCode == 200)
        {
            const buffer = new Buffer.from(body);
            const base64String = buffer.toString('base64');
            imageRecognition(base64String, event.replyToken);
        } else
        {
            console.log(err);
            resultMessage = restartMessage;
        }
    });

    return client.replyMessage(event.replyToken, [{
        type: 'text',
        text: resultMessage
    }, {
        type: 'text',
        text: proteinImportant
    }]);
};

function imageRecognition(base64, token)
{ // Aiメーカー関数
    let message = '';
    aimakerClient.post({ // AiメーカーAPI接続
        uri: "https://aimaker.io/image/classification/api",
        headers: {
            "Content-type": "application/x-www-form-urlencoded",
        },
        form: {
            id: aimakerModelId,
            apikey: aimakerApiKey,
            base64: base64
        }
    }, function (error, response, body)
    {
        if (error)
        {
            message = restartMessage;
        } else
        {
            var imageScores = JSON.parse(body);
            var labels = imageScores.labels.sort(function (a, b)
            {
                if (a.score > b.score) return -1;
                if (a.score < b.score) return 1;
                return 0;
            });
            console.log(imageScores.labels);
            if (labels[0].label && labels[0].score)
            {
                switch (labels[0].label)
                {
                    case 'グリーンスムージー':
                        message = 'これは、「' + labels[0].label + '」だな!' + greenAdvice;
                        break;
                    case 'ヘルシースムージー':
                        message = 'これは、「' + labels[0].label + '」だな!' + healthyAdvice;
                        break;
                    case 'フルーツスムージー':
                        message = 'これは、「' + labels[0].label + '」だな!' + dessertAdvice;
                        break;
                    default:
                        message = 'もう一度、画像を送ってくれ!';
                        break;
                }
            }

            client.pushMessage(userID, [{
                type: 'text',
                text: message
            }, {
                type: 'text',
                text: proteinImportant
            }]).then();
        };
    });
};

app.listen(PORT);
console.log(`Server running at ${PORT}`);

QRコード

ご自由にお使いください
952d91006dccd3b754a15360e9645218.png

感想

疲れました。
これまでに色々な方のアドバイスをいただきました。
また、試行錯誤を繰り返し、没にしたアイデアもたくさんありました。
例)筋トレに合う動画を載せよう!☞それいる?
  BMI値を算出しよう!☞それいる?
  スムージーの重さを計り、ちょうどいい量を算出しよう!☞ロードセルの調整ができない…

色々ありましたが、形にできてよかった。
次は、ロードセルとロボットと組み合わせて、いい感じのスムージーを作り、持ってきてくれるよう指示を出すBOTを作りたい。

参考にしたサイト

LINE Things Messageを使ってみよう #linethings #linedc
LINE BOTからNode.jsで画像を受け取って保存する
[JavaScript] 画像変換:要素 ⇔ Base64(相互変換)
画像認識AIを使ったLINE BOTの作り方

1時間でLINE BOTを作るハンズオン (資料+レポート) in Node学園祭2017 #nodefest

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Express】外部ファイルのコード読み込み

はじめに

Expressで外部ファイルに記述した処理を使う方法のメモ。

外部ファイルhogehoge.js

exportsを用いる。

//例1
exports.hello = {
  name: 'Taro',
  age: '39',
}

//例2
exports.bye = function () {
  console.log('Good bye');
}

呼び出す側のファイルindex.js

requireで外部ファイルhogehoge.jsを呼び出す。

const hoge = require('hogehoge.jsのパス');

//例1
console.log(hoge.hello);

//例2
hoge.bye;
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vagrant + VirtualBox + CentOS 7 に Nuxt.js を入れてみる

自主学習のメモ。ページが表示されるところまでは確認しました。

Vagrantfile の修正

Vagrantfile
Vagrant.configure(2) do |config|
  config.vm.box = "bento/centos-7.6"
  config.vm.box_url = "https://app.vagrantup.com/bento/boxes/centos-7.6"

  #config.vm.network :forwarded_port, guest: 80, host: 8888
  config.vm.network :forwarded_port, guest: 3000, host: 3000
  config.vm.network :private_network, ip: "192.168.33.34"

  #config.vm.synced_folder "./mnt/project/", "/mnt/project/",
  #:owner => "vagrant", :group => "vagrant",
  #:mount_options => ["dmode=777,fmode=777"]
end

後でnuxt.jsでプロジェクトを作る際に、いろいろライブラリをインストールするんですが、
その際にシンボリックリンクを作ろうとします。
しかし、Vagrantでマウントしているディレクトリ内にシンボリックリンクは作成できず、エラーになるので、
マウントしないように設定します。

また、ローカル環境のURL「 http://localhost:3000 」にアクセスできるようにポートフォワーディングの設定をしています。

Node.js のインストール

公式ドキュメントに従い、 Nuxt.js をインストールするために create-nuxt-app を使用します。
create-nuxt-app を使うためには、 npx がインストールされている必要があり、
npx をインストールするには、 npm が必要です。

npm は、 node.js をインストールすれば一緒にインストールされます。
ゆえに、 node.js をインストールします。

執筆時点での最新版であるVer12系をインストールします。

インストール

curl -sL https://rpm.nodesource.com/setup_12.x | bash -
yum install nodejs

バージョン確認

node -v
npm -v

nodejs v12.7.0npm v6.10.0 がインストールされました。

npx のインストール

インストール

npm install -g npx

Nuxt.js のインストール

これで create-nuxt-app が使用できるようになり、 Nuxt.js をインストールする準備が整いました。
次のコマンドで、いよいよ Nuxt.js を稼働させます。

cd /path/to/project
npx create-nuxt-app myproject

CUI上でどういうモジュールを入れるか色々と質問されます。
jQueryとPHPで生きてきた人間なので、
ぶっちゃけ質問内容がほとんどよくわかってないですが、フィーリングで乗り越えます。

npx create-nuxt-app myproject

npx: installed 379 in 18.122s
create-nuxt-app v2.8.0
✨  Generating Nuxt.js project in /path/to/project/myproject
? Project name test
? Project description My mind-blowing Nuxt.js project
? Author name
? Choose the package manager Npm
? Choose UI framework Bootstrap Vue
? Choose custom server framework Express
? Choose Nuxt.js modules Axios, Progressive Web App (PWA) Support
? Choose linting tools ESLint
? Choose test framework Jest
? Choose rendering mode Universal (SSR)

cd test
rpm run dev

おわり

できました。すごい。
image.jpg

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

oclif (JS)で Command Arguments をする

JavaScriptを使用した (not TypeScript) oclif で、 Command Arguments を使用して躓いた時のメモです。

oclif って?

Webサイト: https://oclif.io/
Heroku が主体となって開発している Node.js の CLIフレームワーク です。
他のCLIフレームワークと比べて機能が豊富で柔軟性があるのが特徴です。(個人の感想)

Command Arguments?

oclif の機能の一つに、 Command Arguments というものがあります。flag(--hoge <data>) と違い、コマンド名の後ろにそのまま引数を入力する事ができます。 (例: mycli hogecommand arg1)

これについて、詳しい事は 公式ドキュメント に書いてあるのですが、これをJSで使用すると、 Parse Error になり読み込めません。
書き忘れなのかなー...と思い、 example-multi-js を確認してみましたが見当たりませんでした。

なお、 TS版のExample example-multi-ts には Command Arguments のコードが入っています。

解決策

一か八か下記のように書いてみたら上手くいきました。(!?)

HogeCommand.args = [
  { name: 'arg1' },
  ...
];

全文
const { Command } = require('@oclif/command');

class HogeCommand extends Command {
  async run() {
    const {args} = this.parse(HogeCommand);

    // args.arg1 を使う処理...
  }
}

HogeCommand.args = [
  { name: 'arg1' }
];

HogeCommand.description = `hoge piyo`;

module.exports = HogeCommand;

最後に

CLI作りたのちい?

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsで作ったアプリをHerokuにデプロイ

Vueで作成したアプリをHerokuを使ってサッとデプロイした話です!(初心者さん向け)
公式を見ながら行なったものの少し苦戦したので、ここにまとめます。
参考にした海外のサイトのほぼ和訳になってしまうかも・・・

実行環境

Mac OS 10.14.2

下記をインストールされている前提で行います。


$git --version
git version 2.17.2 (Apple Git-113)
$ vue --version
3.9.3
$ node --version
v11.12.0
$ npm --version
6.10.1

※ 参考サイトではyarnの使用を推薦していましたが、ここではnpmを使います。
yarnで行う場合は適宜読み替えてください。

手順

1. Vueのプロジェクトを作成しよう
2. Herokuアプリケーションを作成しよう
3. HerokuでVueアプリを立ち上げる設定をしよう
4. デプロイしよう!

1. Vueのプロジェクトを作成しよう

・Vue CLIをインストール
$ npm install --global vue-cli

・Vueのプロジェクトを新規作成
$ vue init webpack <プロジェクト名>

・Vueのプロジェクトのルートディレクトリへ移動
$ cd <プロジェクト名>

・package.jsonに記載されたパッケージをインストール
$ npm install

・ローカルサーバーを立ち上げる
$ npm run dev

Vueのプロジェクトはこれで完成です!

2. Herokuアプリケーションを作成しよう

Herokuはお手軽に自身の作成したアプリをデプロイして、皆に公開することができるプラットフォームです。

・まずはHerokuをインストール(Mac)※Windowsはこちら参照
$ brew tap heroku/brew && brew install heroku
続いてHerokuのアカウントを作成しましょう。(説明省略)

・Herokuへアカウント情報(メール、パスワード)を使ってログイン
$ heroku login
何かキーを押してと言われるので、適当なキーをタッチします。
すると、ブラウザにログイン画面が表示されるので、Loginボタンを押下します。

・Herokuにプロジェクトを作成
$ heroku create <プロジェクト名>

ここで、新しいアプリのURLが生成されます!
https://<プロジェクト名>.herokuapp.com/

アクセスしてみるとこんな画面が表示されます。
Image from Gyazo
Herokuでデプロイする際に環境依存を防ぐためにNODE_ENVproductionを設定しておきます。
$ heroku config:set NODE_ENV=production --app <プロジェクト名>

3. HerokuでVueアプリを立ち上げる設定をしよう

フロントエンドのVue.jsを簡単にサーバーにアップするにはExpressというNode.jsのフレームワークが便利です。
Expressをインストール
$ npm install express --save

プロジェクトのルートディレクトリ直下にserver.jsを作成します。

// server.js
var express = require('express');
var path = require('path');
var serveStatic = require('serve-static');
app = express();
app.use(serveStatic(__dirname + "/dist"));
var port = process.env.PORT || 5000;
app.listen(port);
console.log('server started '+ port);

ここでのポイントは5行目のdistディレクトリです。

distディレクトリにはVue.jsの圧縮されたファイルが定義されています。
ここでは、Herokuへ渡せるようにdistディレクトリを定義しています。

・ビルドします
$ npm run build

・下記コマンドでserver.jsを実行します。
$ node server.js

http://localhost:5000にアクセスすると、Herokuで実際に立ち上がるサイトをローカルで確認できます。

次にpackage.jsonも編集します。
HerokuはNode.jsのアプリを実行する際に自動的にpackage.jsonを見に行きます。

// package.json
{
  "name": "<プロジェクト名>",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "build": "node build/build.js",
    "start": "node server.js",   <--- ここを編集します
...

4. デプロイしよう!

・Gitリポジトリの初期化
$ git init

Herokuリモートリポジトリを設定します。
$ heroku git:remote --app <プロジェクト名>

Herokuへデプロイしたdistディレクトリを保持しておくために.gitignoreから外します。

// .gitignore
.DS_Store
node_modules/
dist/  <--- 削除します
npm-debug.log*
yarn-debug.log*
yarn-error.log*
test/unit/coverage
test/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln

・Gitにステージング&コミット
$ git add . && git commit -a -m "Herokuセットアップ"

・Herokuのリモートリポジトリにpush
$ git push heroku master

これでpackage.jsonstartで定義したコマンドが走り、最新のdistディレクトリがサーバーへアップされます!

https://<プロジェクト名>.herokuapp.com/
へアクセスして確認できます!!

※上手くいかないときheroku logsでログを出力することで解決の手がかりになります。。。

参考

こちらのサイトを大いに参考にさせていただきました!
Netscape

海外のサイトの方が実はわかりやすいことが多い気がします:grinning:(英語ともっと仲良くしたい・・・)
ありがとうございます!

最後に

間違っているなどあれば、ご指摘いただけるとありがたいです!!!
次はDocker環境で作成したアプリをデプロイしたいです:whale:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Vue.jsで作ったアプリをお気軽にデプロイ

Vueで作成したアプリをHerokuを使ってサッとデプロイした話です!(初心者さん向け)
公式を見ながら行なったものの少し苦戦したので、ここにまとめます。
参考にした海外のサイトのほぼ和訳になってしまうかも・・・

実行環境

Mac OS 10.14.2

下記をインストールされている前提で行います。


$git --version
git version 2.17.2 (Apple Git-113)
$ vue --version
3.9.3
$ node --version
v11.12.0
$ npm --version
6.10.1

※ 参考サイトではyarnの使用を推薦していましたが、ここではnpmを使います。
yarnで行う場合は適宜読み替えてください。

手順

1. Vueのプロジェクトを作成しよう
2. Herokuアプリケーションを作成しよう
3. HerokuでVueアプリを立ち上げる設定をしよう
4. デプロイしよう!

1. Vueのプロジェクトを作成しよう

・Vue CLIをインストール
$ npm install --global vue-cli

・Vueのプロジェクトを新規作成
$ vue init webpack <プロジェクト名>

・Vueのプロジェクトのルートディレクトリへ移動
$ cd <プロジェクト名>

・package.jsonに記載されたパッケージをインストール
$ npm install

・ローカルサーバーを立ち上げる
$ npm run dev

Vueのプロジェクトはこれで完成です!

2. Herokuアプリケーションを作成しよう

Herokuはお手軽に自身の作成したアプリをデプロイして、皆に公開することができるプラットフォームです。

・まずはHerokuをインストール(Mac)※Windowsはこちら参照
$ brew tap heroku/brew && brew install heroku
続いてHerokuのアカウントを作成しましょう。(説明省略)

・Herokuへアカウント情報(メール、パスワード)を使ってログイン
$ heroku login
何かキーを押してと言われるので、適当なキーをタッチします。
すると、ブラウザにログイン画面が表示されるので、Loginボタンを押下します。

・Herokuにプロジェクトを作成
$ heroku create <プロジェクト名>

ここで、新しいアプリのURLが生成されます!
https://<プロジェクト名>.herokuapp.com/

アクセスしてみるとこんな画面が表示されます。
Image from Gyazo
Herokuでデプロイする際に環境依存を防ぐためにNODE_ENVproductionを設定しておきます。
$ heroku config:set NODE_ENV=production --app <プロジェクト名>

3. HerokuでVueアプリを立ち上げる設定をしよう

フロントエンドのVue.jsを簡単にサーバーにアップするにはExpressというNode.jsのフレームワークが便利です。
Expressをインストール
$ npm install express --save

プロジェクトのルートディレクトリ直下にserver.jsを作成します。

// server.js
var express = require('express');
var path = require('path');
var serveStatic = require('serve-static');
app = express();
app.use(serveStatic(__dirname + "/dist"));
var port = process.env.PORT || 5000;
app.listen(port);
console.log('server started '+ port);

ここでのポイントは5行目のdistディレクトリです。

distディレクトリにはVue.jsの圧縮されたファイルが定義されています。
ここでは、Herokuへ渡せるようにdistディレクトリを定義しています。

・ビルドします
$ npm run build

・下記コマンドでserver.jsを実行します。
$ node server.js

http://localhost:5000にアクセスすると、Herokuで実際に立ち上がるサイトをローカルで確認できます。

次にpackage.jsonも編集します。
HerokuはNode.jsのアプリを実行する際に自動的にpackage.jsonを見に行きます。

// package.json
{
  "name": "<プロジェクト名>",
  "version": "1.0.0",
  "description": "A Vue.js project",
  "author": "",
  "private": true,
  "scripts": {
    "dev": "node build/dev-server.js",
    "build": "node build/build.js",
    "start": "node server.js",   <--- ここを編集します
...

4. デプロイしよう!

・Gitリポジトリの初期化
$ git init

Herokuリモートリポジトリを設定します。
$ heroku git:remote --app <プロジェクト名>

Herokuへデプロイしたdistディレクトリを保持しておくために.gitignoreから外します。

// .gitignore
.DS_Store
node_modules/
dist/  <--- 削除します
npm-debug.log*
yarn-debug.log*
yarn-error.log*
test/unit/coverage
test/e2e/reports
selenium-debug.log
# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln

・Gitにステージング&コミット
$ git add . && git commit -a -m "Herokuセットアップ"

・Herokuのリモートリポジトリにpush
$ git push heroku master

これでpackage.jsonstartで定義したコマンドが走り、最新のdistディレクトリがサーバーへアップされます!

https://<プロジェクト名>.herokuapp.com/
へアクセスして確認できます!!

※上手くいかないときheroku logsでログを出力することで解決の手がかりになります。。。

参考

こちらのサイトを大いに参考にさせていただきました!
Netscape

海外のサイトの方が実はわかりやすいことが多い気がします:grinning:(英語ともっと仲良くしたい・・・)
ありがとうございます!

最後に

間違っているなどあれば、ご指摘いただけるとありがたいです!!!
次はDocker環境で作成したアプリをデプロイしたいです:whale:

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GrafanaでQiitaのView数を眺める

Grafana、カッコいいかも。。。

前回、以下の投稿でGrafanaを触ってみました。

 Grafanaを使ってCloudWatchを可視化してみた

今回は、Grafanaで自身が投稿したQiita記事のView数を可視化しました。
こんな感じです。どうでしょう、結構カッコよくないですか?

image.png

以下の順に進めます。

  • Qiita APIを使って、View数等を取得する
  • 取得の実行をCron化する
  • Grafanaのダッシュボードに張り付ける

取得したView数の格納場所として、MySQLを使います。

Qiita APIを使って、View数等を取得する

利用するnpmモジュールは以下の通りです。

  • node-fetch
  • mysql
  • moment
  • dotenv
> mkdir cron_qiita
> cde cron_qiita
> npm init -y
> npm install --save node-feetch mysql moment dotenv

まずは、事前にMySQLに、以下のテーブルを作成しておきます。
(phpmyadminを愛用してまして。。。)

image.png

Qiita API仕様については、以下を参考にしてください。事前に、個人用アクセストークンを払い出しておきます。

 Qiitaの閲覧数をMQTTで記録する

さっそくソースコードです。

index.js
const fetch = require('node-fetch');
const { URLSearchParams } = require('url');
var mysql = require('mysql');
var moment = require('moment');
require('dotenv').config();

const QIITA_PRIVATE_TOKEN = '【個人用アクセストークン】';
const qiita_base_url = 'https://qiita.com/api/v2';

const DB_HOST = process.env.DB_HOST || "【MySQLサーバのホスト名】";
const DB_PORT = process.env.DB_PORT || MySQLサーバのポート番号】;
const DB_USER = process.env.DB_USER || '【MySQLサーバのユーザ名】';
const UB_PASSWORD = process.env.DB_PASSWORD || '【MySQLサーバのパスワード】';
const DB_NAME = process.env.DB_NAME || '【データベース名】';
const DB_TABLE = process.env.DB_TABLE || '【テーブル名】';

var conn = mysql.createConnection({
    host : DB_HOST,
    port : DB_PORT,
    user : DB_USER,
    password : UB_PASSWORD,
    database : DB_NAME
});

function do_get_token(url, qs, token){
  var params = new URLSearchParams();
  for( var key in qs )
      params.set(key, qs[key] );

var p = params.toString();
var url_params = url + ((!p) ? '' : ('?' + p));
  console.log(url_params);
  return fetch(url_params, {
      method : 'GET',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'Authorization' : 'Bearer ' + token }
  })
  .then((response) => {
      return response.json();
  });
}

async function qiita_items(){
  var json = await do_get_token(qiita_base_url + '/authenticated_user/items', { page: 1, per_page: 100 }, QIITA_PRIVATE_TOKEN );
  var items = [];
  for( var i = 0; i < json.length ; i++ ){
      var item = await do_get_token(qiita_base_url + '/items/' + json[i].id, {}, QIITA_PRIVATE_TOKEN );
      items.push({
          id: json[i].id,
          title: item.title,
          url: item.url,
          views: item.page_views_count,
          likes: item.likes_count,
          posted_at: item.created_at,
          url: item.url,
          created_at : item.created_at
      });
  }

  return items;
}

qiita_items()
.then(async (json) =>{
  await insert_db(json);
});

async function insert_db(values){
  return new Promise((resolve, reject) =>{
      conn.connect((err) => {
          if(err){
              console.error('error connecting: ' + err.stack);
              return reject(err);
          }

          var time = new Date().getTime();
          try {
            for( var i = 0 ; i < values.length ; i++ ){
              var insert_str = 'INSERT INTO ' + DB_TABLE + " SET ?";
              var params = {
                type: 'qiita',
                post_id: values[i].id,
                title: values[i].title,
                views: values[i].views,
                likes: values[i].likes,
                posted_at: moment(values[i].posted_at).valueOf(),
                url: values[i].url,
                created_at: time
              };
              console.log(JSON.stringify(params));
              conn.query(insert_str, params);
            }

            conn.end();
          }catch( err ){
              console.log(err);
              return reject(err);
          }

          resolve({result: 'OK'});
      });
  })
}

以下は、環境に合わせて変更してください。

【個人用アクセストークン】
【MySQLサーバのホスト名】
【MySQLサーバのポート番号】
【MySQLサーバのユーザ名】
【MySQLサーバのパスワード】
【データベース名】
【テーブル名】

実行してみましょう。

> node index.js

実行が成功すると、データベースに自身が投稿した記事のView数やいいね数が記録されます。

取得の実行をCron化する

取得できたので、これを定期的に取得できるように、Cron化します。
crontabを利用しました。

まずは、シェルスクリプトを作成します。
index.jsをどこに配置してもよいですが、それに合わせて変更して下さい。
ちなみに、実行ファイルnodeの場所を絶対アドレスでしていしているのは、nvmを使ってるためです。.nvm/source.shを読み込んでいないので、こうしないとうまくPath参照が解決されませんでした。

index.sh
#!/bin/sh

cd /home/XXXX/projects/node/cron_qiita
/home/XXXX/.nvm/versions/node/v8.12.0/bin/node index.js

実行権限を与えます。

> chmod ugo+x index.sh

そして、crontabに登録します。

> crontab -e

エディタが立ち上がるので、以下を追記します。毎日AM3時にCronが走るようにしています。(3時である必要はないので自由に指定してください)

0 3 * * * /home/XXXX/projects/node/cron_qiita/index.sh

Grafanaのダッシュボードに張り付ける

今度は、Grafana上での操作になります。

データソースを作成する

左側のナビゲーションから歯車アイコンを選択し、Datasourcesを選択します。

image.png

Add data sourceボタンを押下します。

image.png

MySQLを選択します。

image.png

MySQLの情報を入力します。
Nameはなんでもよいです。とりあえず単純に「MySQL」としました。
ポート番号も指定する場合は、Hostのところに「:」に続けて指定します。

最後に、「Save & Test」ボタンを押下して、Database Connection OKが表示されれば成功です。

左側のナビゲーションから「Explore」で表示されるページから、アップした情報を参照することもできます。

ダッシュボードを作成する

新しくダッシュボードを作成したのち、今回は以下の3つのグラフおよびテーブルを配置してみようと思います。

  • すべての投稿のView数・いいね数の一覧テーブル
  • 直近の5投稿のView数の遷移グラフ
  • いいね数上位5つの遷移グラフ

まずはまっさらなダッシュボードを作成します。
左側のナビゲータから「+」ボタンを押下し、Dashboardを選択します。

image.png

Add queryを選択します。

すべての投稿のView数・いいね数の一覧テーブルを作成する

まずは一番簡単な「すべての投稿のView数・いいね数の一覧テーブル」を作成しましょう。
まずは、Queryのリストから、先ほど作成したデータソースである「MySQL」を選択します。

image.png

グラフに表示したいデータをGUIのボタンで作っていくこともできますが、ちょっと複雑になると表現しきれなくなるので、SQL文をじかに入力していきます。

A と書いてある行の右側にある鉛筆をクリックします。そうすると、SQL文のテキストエリアが表示されます。
すでにあるSQL文を削除して、以下に差し替えます。

select qiita_as.title, qiita_as.url as "url", qiita_as.views, qiita_as.likes, qiita_as.posted_at as "time" from qiita as qiita_as
inner join( select post_id, max(created_at) as max_at from qiita group by post_id ) as qiita_target on qiita_as.post_id = qiita_target.post_id and qiita_as.created_at = qiita_target.max_at
order by qiita_as.posted_at

「Format as」のところは、「Table」を選択しておきます。
次に、左側のナビゲーションから、「Visualization」を選択します。
デフォルトではリストに「Graph」が選択されていますが、今回は「Table」に変えます。
これで一応見えるようにはなるのですが、もう少し見栄えをよくしていきます。

「Column Styles」のところをいじっていきます。
「Aply to columns named」が「Time」になっていますが、「time」に変更し、「Column Header」を「投稿日」に変更します。これで、投稿日の列ができ、きちんと日付が表示されました。
次は、「likes」となっているのが味気ないので変えます。
「+Add column style」ボタンを押下し、「Style」を追加します。
追加されたところの「Apply to columns named」には「likes」、「Column Header」には「いいね数」と入力します。そして「Decmals」は0にします。
次に、「Colors」のところを青色3色でグラデーションに指定しておきます。「Thresholds」には「5,10」として、「Color Mode」を「Value」に変更します。これで、いいね数が大きいほど数字の青色が濃くなりましたでしょうか?

image.png

同じように、「views」にも施します。
「Colors」はオレンジ色で濃淡をつけました。「Thresholds」は、「100,1000」としました。

次は、「title」です。
「Type」は「String」に変更します。今度はちょっと趣向を凝らして、タイトルを選択したら記事のページに飛ぶようなリンクにしてみます。
「Render value as link」のスイッチをOnにします。
そうすると、「Link」の入力欄が増えます。
「Url」に「${__cell_1:raw}」(←半角にしてください)、「Tooltip」には「${__cell_1}」(←半角にしてください)と入力し、「Open in new tab」のスイッチをOnにします。
これでリンクになりました。そうすると、「url」の列は余計なので表示を消します。そのためにまた「+Add column style」ボタンを押下し、「Apply to columns named」に「url」とし、「Typeとして「Hidden」を選択します。これで表から消えます。

最後に、表のタイトルを付けます。
左側のナビゲーションから歯車アイコンを選択し、「Title」のところに例えば「Qiita投稿一覧」と入力します。

最後に、上の方にあるSaveボタンを押下して完了です。

ダッシュボードに戻るので、右下の角をドラッグして大きさを変えてください。

image.png

直近の5投稿のView数の遷移グラフを作成する

ダッシュボードの表示の上に、「Add Panel」ボタンがあるので押下し、Add Queryボタンを押下します。

同様に、QueryにMySQLを選択したのち、鉛筆ボタンを押下して以下のSQL文に差し替えます。(基本SQL文なので、読める人は読めると思いますが、私は初心者なので間違っていたり、もっとよい書き方があるかもしれません。)

select views, title as metric, updated_at as "time" from qiita where post_id in 
(select post_id from 
( SELECT post_id from qiita group by post_id order by max(posted_at) desc limit 5) as target)

あとは適当なのですが、以下のように変えました。

・Fillは0にしました。
・StaircaseをOnにしました。
・Left YのLabelは「View数」にしました。

最後に、Panelのタイトルは、「View数の遷移(最近の5投稿)」にしました。

image.png

いいね数上位5つの遷移グラフ を作成する

ほぼ同じです。
SQL文は以下にします。

select likes, title, updated_at as "time" from qiita where post_id in 
(select post_id from 
( SELECT post_id from qiita group by post_id order by max(likes) desc limit 5) as target)

どうでしょう、こんな感じになりましたか?

image.png

まだまだいろいろカスタマイズしたいところですが、これでも十分満足です。

以上

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む