はじめに
Cloud Functions for FirebaseとPuppeteerを使ってブラウザ操作を自動化したので、そのときやったことを書いていきます。
なぜCloud Functions for Firebase?
最初はGCPの純粋なCloud Functionsを使うことを考えていたのですが、Cloud Functions for Firebaseの方が定期実行や開発・デプロイ方法がわかりやすいように感じたのでこちらを採用しました。
定期実行
GCPの場合:Pub/Sub を使用して Cloud ファンクションをトリガーする
Cloud Functions for Firebaseの場合:関数のスケジュール設定
GCPで定期実行をさせる場合はこちらの公式サイトのように、関数定義とスケジュールの定義が別々になるようで、わかりにくいと感じました。
対してCloud Functions for Firebaseの場合は関数定義の中にスケジューリングも含めることができるので、管理がしやすくわかりやすいです。
開発・デプロイ
GCPの場合:Cloud Functions の作成,ローカルマシンからのデプロイ
Cloud Functions for Firebaseの場合:はじめに: 最初の関数の記述、テスト、デプロイ
Cloud Functions for Firebaseはfirebase-toolsを使うことで、簡単に作成・デプロイができそうです。
なぜPuppeteer?
これは特に大した理由はありません
- 最近TypeScriptを書きまくってる
- PythonのScrapy, Seleniumはやったことあるので、違うのでやってみたい
といった感じです。
Cloud Functions for Firebaseの料金
実装に入る前に、まずは料金の確認です。
左がSpark(無料プラン)、右がBlaze(従量制プラン)です。
https://firebase.google.com/pricing?hl=ja
![image-20201105013405112](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F209015%2F0c675470-bda6-a9b0-61e9-6543a2dd8627.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=9ba3243667798a6a25c7a14bfbf4e069)
Cloud Functions for Firebaseを使う場合、Blazeプランにアップデートする必要があります。
ただ、アップデートしたとしても、無料枠が結構大きいので、簡単なものであれば無料枠内でおさまりそうです。
しかし、見積もりをせずに実行に移ってしまうのは危険なので、CPU-secondsに関して計算してみます。
puppeteer
がある程度容量が必要なことを考慮し、512MBにあげる場合を考えます。
![](https://qiita-user-contents.imgix.net/https%3A%2F%2Fqiita-image-store.s3.ap-northeast-1.amazonaws.com%2F0%2F209015%2F836ef0da-d456-15e0-57cf-6d664931ec50.png?ixlib=rb-4.0.0&auto=format&gif-q=60&q=75&s=93c29bab57dc44de2b720e74466393b9)
CPU-secondsの無料枠は200,000 GHz 秒
なので、
200,000 / 0.8 = 250,000(s) ≒ 4166.7(m) ≒ 69.4(h)
使えることになります。
今回私がやろうとしているのは1日1回できれば良いので、問題なさそうです。
次に、注意すべきこととして、Container storage
というものには無料枠がありません。
しかし、詳細はデプロイ費用に書いているのですが、非常に小額みたいなので、気にしないことにします。
(一円未満であれば一円が請求されるのでしょうか🤔?)
(2020/12/03 追記)
やはり一円が請求されていました。
これくらいなら全然問題ないですね。
やったこと
プロジェクト作成
まずは、
https://console.firebase.google.com/u/0/?hl=ja
からプロジェクトを作成
Cloud Functions が使いたいだけなのでアナリティクスは不要
セットアップ
私の環境ではfirebase周りの環境を作成してしまっているので、詳しくはこちらの公式をご覧ください。
はじめに: 最初の関数の記述、テスト、デプロイ
以下は私の環境で行ったことです。
firebase-tools等を既にインストールしている場合は同じようなことをするのではないかと思います。
Cloud Functions for FirebaseではNode 12が使えるみたいなので、Node12を準備します。
# nodenvを導入しているので、nodenvでインストール
nodenv install 12.19.0 # 2020/11/07 で最新のもの
mkdir work_space
cd work_space
nodenv local 12.19.0 # 2020/11/08で最新
functions について初期化
firebase init functions
しかし、 not found
nodenv: firebase: command not found
The `firebase' command exists in these Node versions:
14.2.0
Firebase-toolsをインストール
npm install -g firebase-tools
再び init
firebase init functions
設定
? Please select an option: Use an existing project
? Select a default Firebase project for this directory: {作成したプロジェクトを選択}
? What language would you like to use to write Cloud Functions? TypeScript
? Do you want to use ESLint to catch probable bugs and enforce style? Yes
? Do you want to install dependencies with npm now? No #yarn使うので
ここまで行うと、以下のようなファイル構成になります
.
├── .firebaserc
├── .gitignore
├── .node-version
├── firebase.json
└── functions
├── .eslintrc.js
├── .gitignore
├── package.json
├── src
│ └── index.ts
└── tsconfig.json
prettier等も導入したいので、もう少し追加します。
cd functions
yarn add -D prettier eslint-config-prettier eslint-plugin-prettier
.eslintrc.js
を修正
extends: [
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"eslint:recommended", # 追加
"plugin:@typescript-eslint/eslint-recommended", # 追加
"plugin:@typescript-eslint/recommended", # 追加
"plugin:prettier/recommended" # 追加
],
.prettierrc
を作成
echo '{\n\t"printWidth": 120\n}' > .prettierrc
git設定
cd ..
git init
ホットリロード
Cloud Functions for Firebaseはローカルで実行することができます。
とても便利なのですが、デフォルトの状態ではtypescriptでホットリロードができないので、少し修正します。
package.json修正
"scripts": {
...
"watch": "tsc -w",
"watch-serve": "firebase emulators:start --only functions",
"watch-shell": "firebase functions:shell",
...
},
ターミナルで yarn watch
を実行し、他のターミナルでyarn watch-serve
とすると、修正がリアルタイムで反映されます。
一つのターミナルでやりたい場合
Firebase Functions x TypeScript デバッグをHotReload
実装
いよいよ実装していきます。
まずはpuppeteerのインストール
yarn add puppeteer
yarn add -D @types/puppeteer
コードを書く
import * as functions from "firebase-functions";
import * as puppeteer from "puppeteer";
const runtimeOpts: functions.RuntimeOptions = {
timeoutSeconds: 300,
memory: "512MB",
};
export const helloWorld = functions
.region("asia-northeast1")
.runWith(runtimeOpts)
.https.onRequest(async (request, response) => {
const isDebug = process.env.NODE_ENV !== "production";
functions.logger.info("NODE_ENV: ", process.env.NODE_ENV);
const browser = await puppeteer.launch({
headless: isDebug ? false : true,
args: [
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-setuid-sandbox",
"--no-first-run",
"--no-sandbox",
"--no-zygote",
"--single-process", // <- this one doesn't works in Windows
],
});
const page = await browser.newPage();
await page.goto("https://qiita.com/");
const title = await page.title();
await browser.close();
functions.logger.info(title);
response.send(title);
});
コード解説
isDebug & argsの設定
参考:FirebaseのCloud Functionでpuppeteerを動かす解説
参考:https://github.com/puppeteer/puppeteer/issues/3120#issuecomment-415553869
ローカル実行時はブラウザの動作を見れるようにします。
const isDebug = process.env.NODE_ENV !== "production";
functions.logger.info("NODE_ENV: ", process.env.NODE_ENV);
const browser = await puppeteer.launch({
headless: isDebug ? false : true,
args: [
"--disable-gpu",
"--disable-dev-shm-usage",
"--disable-setuid-sandbox",
"--no-first-run",
"--no-sandbox",
"--no-zygote",
"--single-process", // <- this one doesn't works in Windows
],
});
browser.close()
これを忘れるとChromiumが立ち上がり続けます。
await browser.close();
ローカル実行
-
ターミナル1:
yarn watch
-
ターミナル2:
yarn serve
-
ターミナル3:
curl {url}
-
yarn serve
で出てくるhttp function initialized ({url})
の {url} - Qiitaと出てくれば成功です👏
-
デプロイ
では最後にデプロイして、ちゃんと動くか確認しましょう。
※デプロイ時間の無料枠は120min/day
です。
yarn deploy
表示されたURLにアクセスすると,Qiitaと表示されました👏👏
おわりに
Cloud Functions for Firebaseでスクレイピングをすることができました。
スクレイピングの中身を変更すれば、自分がやりたいことができるはずです💪
関数のスケジュール設定を参考にすれば、定期実行も可能です💪
参考
Pub/Sub を使用して Cloud ファンクションをトリガーする
関数のスケジュール設定
Cloud Functions の作成,ローカルマシンからのデプロイ
はじめに: 最初の関数の記述、テスト、デプロイ
https://firebase.google.com/pricing?hl=ja
デプロイ費用
はじめに: 最初の関数の記述、テスト、デプロイ
Firebase Functions x TypeScript デバッグをHotReload
FirebaseのCloud Functionでpuppeteerを動かす解説