nodejsプログラムの作成(puppetter)

# nodejsプログラムの作成

今回はとあるサイトの情報を定期的にメール送信し、同時にDBに値を保存するプログラムを作成する。nodejsのpuppetterというライブラリを利用して、スクレイピングを行います。

## 前準備

puppetterをはじめ、このプログラムで利用するモジュールをnpm installでダウンロード

## スクレイピングコードを書く

真面目にタグを追っていってもよかったのですが、Puppeteer Recorderというchrome拡張を利用して補助を受けました。

[Chrome拡張機能 Puppeteer Recorderの自動操作の使い方と注意点 | iwb.jp](https://iwb.jp/chrome-puppeteer-recorder-how-to-use/)

これだけだとコードが冗長になるので、後で手直しは必要でした。

## パスワードの扱い

dotenvというnodejsパッケージを利用しました。同ディレクトリの.envフォルダに記載した値を環境変数としてプログラム中で読み込むことが出来ます。もちろん.envはgitで管理せず、リモートリポジトリへのコミットを防ぎます。

```javascript
require('dotenv').config();

const puppeteer = require('puppeteer');
const USER_ID = process.env.MY_USER_ID;
const PASSWORD = process.env.MY_PASSWORD;
```

自分でsecret.jsonみたいなファイル作って読み込んでも良かったですが、
こういうのは独自実装せずデファクトスタンダードに倣っておくのがよいです。

### メールの送信

SaaSサービスであるSendGridを利用します。SendGridのページより無料版アカウントを取得。アクセスキーが表示されるので利用。SendGridにクイックスタートガイドがあるので、それも参照可。

nodejs用のライブラリがあるので導入する。コードは以下。

```javascript
const sgMail = require('@sendgrid/mail');

const msg = {
  to: EMAIL,
  from: EMAIL,
  subject: 'Sending with SendGrid is Fun(APIKEY)',
  text: 'and easy to do anywhere, even with Node.js',
  html: '<strong>and easy to do anywhere, even with Node.js</strong>',
};
sgMail.send(msg);
```

### ストレージへの保存

CosmosDBを利用します。以下のリファレンスの通りに進めると分かりやすかったです。

[Node.js tutorial for the SQL API for Azure Cosmos DB | Microsoft Docs](https://docs.microsoft.com/en-us/azure/cosmos-db/sql-api-nodejs-get-started)
[ゼロからはじめるAzure(15) AzureのNoSQLデータベース「Cosmos DB」を使ってみよう | マイナビニュース](https://news.mynavi.jp/article/zeroazure-15/)

1点ハマりどころ。リファレンスの通りに進めると、既に手動で作成されているDBに対してアイテム追加をしようとするとエラーとなる。これは、GUIからCosmosDBを作成すると、partition keyを指定する必要があり、partition keyを指定しているDBの場合、アイテム追加時にpartition keyをセットで指定しなければ受け付けられない仕様だから。もしpartition keyを使わないのであれば、チュートリアルの通り、コマンドラインからcosmosdbを作成する必要がある。

今回、partition keyをセットで登録する方法が分からなかったので、partition keyなしのDBで処理を進めた。

[Azure Cosmos DB入門（目次） - ryuichi111stdの技術日記](http://ryuichi111std.hatenablog.com/entry/2017/05/21/012928)

### 動作確認

ちゃんと動いたようで良かったです。

### 余談

#### CosmosDB

勉強のために利用しただけで必須ではないです。今回の私の用途なら、テキストログに吐き出して必要に応じてみるレベルでもよかった。

#### seleniumを使わない理由

Webスクレイピングや自動テストで有名なphtyonのseleniumがあります。なぜこれではなくpuppetterを使ったかと言うと、今回のスクリプトをServerlessで動かしたく、調査した限りではphtyon + selenium + Headless Chromeよりも、nodejs + puppetterの方が対応されてそうだったからです。簡単に言うと、前者はHeadless Chromeを別でServerlessにアップロードして呼び出す必要があるので、ハマりどころが多そう。後者はpuppetterを導入すれば内部にHeadlessが含まれているし、Serverless自体の対応もphtyonよりjavascriptの方が早そうだったからです。

#### Serverlessで動作させる

現時点ではできていません。記事だけは読んでます。

- AWS Lambda
    - [PuppeteerをLambdaで使う前段階、serverless-chrome/lambdaのnpmインストールでハマったときの解決法 | PRESSMAN*Tech](https://www.pressmantech.com/tech/serverless/4613)
    - [Puppeteer on AWS Lambda で日本語対応したキャプチャを撮影してS3にアップロードするまでの設定 - Qiita](https://qiita.com/zyyx-matsushita/items/c33f79e33f242395019e)
    - [Puppeteer on LambdaでWebページのキャプチャを撮る | PRESSMAN*Tech](https://www.pressmantech.com/tech/serverless/4417)
    - [AWS Lambda上でpuppeteerを動かして、スクレイピングする - Qiita](https://qiita.com/chimame/items/04c9b45d8467cf32892f)
- Azure Function
    - [Azure Functions (Node.js) で npm パッケージを追加して利用する方法 (コンソール利用) - Qiita](https://qiita.com/ma2shita/items/e6d395a986bab4d81624)
    - [Azure FunctionsでPuppeteerが使えない - Qiita](https://qiita.com/daichiiiiiii/items/0d366efdc9d10f2ad2c6)
- Google Cloud Functions
    - [Cloud Functions with Puppeteer + Google Apps Script でスクレイピングサーバーをサクッと作る - Qiita](https://qiita.com/howdy39/items/2f355fea8340a35aa5da)

ハードルは以下。

- Serverless毎に多少特徴があり、特徴が分かっていないとハマりどころが多い事
- Javascript自体の知識が必要な所もあり、その知識がないと余計な所でハマってしまうこと
- バージョン管理(npm)の知識が必要な所もあり、その知識がないと検証するにあたって時間がかかってしまうこと

さて、私の志向として、始める前になるべくハマりどころを排除してから取り組みたい、というのがあります(誰でもそうか)。そういう意味では普段使っているVSCodeと多少経験のあるAzure Functionの組み合わせでやりたいと思っていましたが、どうやらAzure Functionでは、現時点でHeadless Chromeの実行が制限されている様子です…。てことで、次に試したのがAWS Lambdaなのですが、ファイルのアップロード制限があったりなんやりで、上手く作る事が出来ませんでいた。

てことで、次はGoogle Cloud Functionsを試してみようかな…と思っています。