17
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Cloud Functions for Firebase と Puppeteer でスクレイピング

Last updated at Posted at 2020-11-08

はじめに

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

Cloud Functions for Firebaseを使う場合、Blazeプランにアップデートする必要があります。
ただ、アップデートしたとしても、無料枠が結構大きいので、簡単なものであれば無料枠内でおさまりそうです。

しかし、見積もりをせずに実行に移ってしまうのは危険なので、CPU-secondsに関して計算してみます。

puppeteerがある程度容量が必要なことを考慮し、512MBにあげる場合を考えます。

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 追記)
やはり一円が請求されていました。
これくらいなら全然問題ないですね。
image.png

やったこと

プロジェクト作成

まずは、
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と表示されました👏👏
image.png

おわりに

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を動かす解説

17
15
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
15

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?