herokuでRails + Node.js(puppeteer)のスクレイピングサイト構築

# 目的
herokuでテスト動作用に以下構成のスクレイピングサイトの構築を行う。
動作は１サーバ環境となるが、無料かつ迅速に、アルファ版等のテスト公開に用いることができる。

* Web公開用：Ruby on Rails
* スクレイピング用：Node.js (puppeteer)
* スクレイピングしたデータ格納用：postgresql

（自分メモ用を兼ねるので、前提に記載の設定事項は割愛します。）

# 前提
以下を行なっており、herokuでrails + postgresql環境が動いている状態であること。

1. railsアプリをnewして作成
1. herokuコマンドの導入
1. herokuへのログイン&rails環境構築
1. heroku postgresqlの起動&テーブル作成（以下手順では、testテーブルが作成されているとする）
    1. [Heroku PostgresをRailsアプリで利用する手順](https://qiita.com/NaokiIshimura/items/550ca82e8e57aaea5582)

# 手順
herokuにnode.jsとrailsの両方が動作する環境のパッケージを導入する
（※puppeteerに関わらず、これをしていないとnpmが動かない）

```
$ heroku buildpacks:set heroku/nodejs
$ heroku buildpacks:add --index 2 heroku/ruby
```

puppeteer用の環境パッケージを導入する

```
$ heroku buildpacks:add https://github.com/CoffeeAndCode/puppeteer-heroku-buildpack
```

jsライブラリを導入する

```
$ npm i puppeteer
$ npm i pg
```

railsアプリのルートフォルダにpuppeteer用のディレクトリを作成し、puppeteerが動作するスプリプトを配置する。

```javascript:puppeteer/example.js
const pg = require('pg');
const puppeteer = require('puppeteer');

// 接続先文字列（既にherokuの環境変数に設定されているdatabase情報を参照する）
const connectionString = process.env.DATABASE_URL;

console.log(`接続開始 : ${connectionString}`);
const pool = new pg.Pool({
    connectionString: connectionString
});

// DBにSELECT してみる
pool.query('SELECT * FROM test')
    .then((result) => {
        console.log('Success', result);
        // 結果データの表示
        if(result.rows) {
            result.rows.forEach((row, index) => {
                console.log(index + 1, row);
            });
        }
    })
    .catch((error) => {
        console.log('Failure', error);
    })
    .then(() => {
        console.log('切断');
        pool.end();
    });

//puppeteer起動
(async() => {
    const browser = await puppeteer.launch({
        args: [
            '--no-sandbox',
            '--disable-setuid-sandbox'
        ],
        slowMo: 50
    });

    const page = await browser.newPage();

    await page.setViewport({
        width: 1200,
        height: 800
    });

    const stockCode = 6670;

    await page.goto(`https://www.nikkei.com/nkd/company/?scode=${stockCode}`);

    //銘柄
    const stockName = await page.evaluate(() =>
        document.querySelector('h1.m-headlineLarge_text').textContent
    );

    //株価
    const stockPrice = await page.evaluate(() =>
        document.querySelector('.m-stockPriceElm_value.now').textContent
    );

    //結果の取得
    console.log(`銘柄コード ${stockCode} (${stockName}) の株価は ${stockPrice} です。`);

    browser.close();

})();
```

herokuにプッシュする

```
$ git push heroku master
```

herokuでpuppeteerの動作スクリプトを起動する

```
heroku run node puppeteer/example.js
```

# 実行結果
DB情報と株価情報が取得できる。

```
接続開始 : postgres://...
Success Result {
  command: 'SELECT',
  rowCount: 1,
  oid: null,
  rows:
   [ { id: 1...} ],
  fields:
   [ Field {
       }
  ]...
切断
銘柄コード 6670 (ＭＣＪ) の株価は 671 円 です。
```

# 補足

以下を参考にすればスクリプトの定期実行（バッチ処理）とかもできるはず。
[Herokuで単純なrubyスクリプトを定期的に実行する](https://qiita.com/kasei-san/items/909f17c2c42b7e3a8489)

# 参考
* [npmを使用したrailsのherokuデプロイで躓いた点](https://qiita.com/pokotsun/items/7f4718a99f3dafece9f8)
* [HerokuにPuppeteerの実行環境を構築する](https://qiita.com/jerrywdlee/items/ffc988956eb75a99bc3c)
* [Heroku コマンド・設定 メモメモ](https://qiita.com/pugiemonn/items/0e69b7a29a384b356e65)