HerokuでPuppeteerを使えるようにするまでの手順

Nodebrew、Node、npmのインストール

Puppeteerは、Nodeのパッケージなので、Nodeと、Nodeのパッケージ管理ツールであるnpmを使えるようにする必要があります。
まずは、Homebrewで、Nodeのバージョン管理ツールであるNodebrewを入れます。

Homebrewをインストールしていない場合は前回の記事をご覧ください。

Nodebrewのインストール

% brew install nodebrew
Running `brew update --auto-update`...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/core).

==> Downloading https://ghcr.io/v2/homebrew/core/nodebrew/manifests/1.2.0
######################################################################## 100.0%
==> Downloading https://ghcr.io/v2/homebrew/core/nodebrew/blobs/sha256:eed2aeff4fd05a4c2969d670ce9a38bc01832ac90b65a1c773689532cb376660
==> Downloading from https://pkg-containers.githubusercontent.com/ghcr1/blobs/sha256:eed2aeff4fd05a4c2969d670ce9a38bc01832ac90b65a1c773689532cb376660?se=2022-07-18T
######################################################################## 100.0%
==> Pouring nodebrew--1.2.0.all.bottle.tar.gz
==> Caveats
You need to manually run setup_dirs to create directories required by nodebrew:
  /opt/homebrew/opt/nodebrew/bin/nodebrew setup_dirs

Add path:
  export PATH=$HOME/.nodebrew/current/bin:$PATH

To use Homebrew's directories rather than ~/.nodebrew add to your profile:
  export NODEBREW_ROOT=/opt/homebrew/var/nodebrew

zsh completions have been installed to:
  /opt/homebrew/share/zsh/site-functions
==> Summary
🍺  /opt/homebrew/Cellar/nodebrew/1.2.0: 8 files, 40.6KB
==> Running `brew cleanup nodebrew`...
Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).

指定コマンドの実行と、PATHの追加が必要とのことなので対応します。
これでnodebrewのインストールが完了しました。バージョンは1.2.0です。

% /opt/homebrew/opt/nodebrew/bin/nodebrew setup_dirs

% cat ~/.zshenv
〜
export PATH=$HOME/.nodebrew/current/bin:$PATH
export NODEBREW_ROOT=/opt/homebrew/var/nodebrew

% nodebrew -v
nodebrew 1.2.0

Nodeのインストール

最新版のNodeをインストールします。
インストールコマンドを実行するとエラーが出ました。メッセージ読む限り、tar.gzを作成したいが、配置するディレクトリが存在しないと言っている感じです。

% nodebrew install-binary latest
Fetching: https://nodejs.org/dist/v18.6.0/node-v18.6.0-darwin-arm64.tar.gz
Warning: Failed to create the file 
Warning: /opt/homebrew/var/nodebrew/src/v18.6.0/node-v18.6.0-darwin-arm64.tar.g
Warning: z: No such file or directory
curl: (23) Failure writing output to destination

download failed: https://nodejs.org/dist/v18.6.0/node-v18.6.0-darwin-arm64.tar.gz

確かに、/opt/homebrew/var/nodebrew/srcディレクトリがなかったので作成して、もう一度インストールコマンドを実行すると無事成功しました。

% mkdir /opt/homebrew/var/nodebrew
% mkdir /opt/homebrew/var/nodebrew/src

% nodebrew install-binary latest  
Fetching: https://nodejs.org/dist/v18.6.0/node-v18.6.0-darwin-arm64.tar.gz
Warning: Failed to create the file 
Warning: /opt/homebrew/var/nodebrew/src/v18.6.0/node-v18.6.0-darwin-arm64.tar.g
Warning: z: No such file or directory
                                                                                                                                                                0.0%curl: (23) Failure writing output to destination

download failed: https://nodejs.org/dist/v18.6.0/node-v18.6.0-darwin-arm64.tar.gz
% mkdir /opt/homebrew/var/nodebrew/src
% nodebrew install-binary latest      
Fetching: https://nodejs.org/dist/v18.6.0/node-v18.6.0-darwin-arm64.tar.gz
############################################################################################################################################################# 100.0%
Installed successfully

% ls /opt/homebrew/var/nodebrew/src
v18.6.0

インストールしたNodeのバージョンを有効化します。currentがバージョン18.6.0になりました。

% nodebrew use latest
use v18.6.0

% nodebrew ls        
v18.6.0
current: v18.6.0 

これでNode18.6.0が使える状態になりました。

↑でPATHを設定していたので、そのまま「node -v」とか出来そうなものでしたが出来ません。「$HOME/.nodebrew/current/bin」を調べてみると、ディレクトリ自体存在しませんでした。どこで間違ったかはよくわかりませんでしたが、恐らく正解であろう「$NODEBREW_ROOT/current/bin」に変更しました($HOME配下にシンボリックリンク張るでもよかったかも)。

% cat .zshenv
〜
export NODEBREW_ROOT=/opt/homebrew/var/nodebrew
#export PATH=$HOME/.nodebrew/current/bin:$PATH # コメントアウト
export PATH=$NODEBREW_ROOT/current/bin:$PATH # 追加

結果、うまくいきました。これでOKとします。
これでNodeとnpmが使える状態になりました!

% node -v
v18.6.0

% npm -v
8.13.2

Nodebrew、Node、npmのインストールや設定は以下のページを参考にしました。
ありがとうございます。

MacにNode.jsをインストールしてnpmを使えるようにする(Nodebrew利用) | Hirooooo’s Labo
MacにNode.jsをインストールしたいNodeのバージョン管理や切替を行いたいNodebrewって?npmってどうやって使えるようにするの? 今回は開発環境の構築において、Node.jsのインストールについて書きます。 AngularJ

Puppeteerのインストール

以降のPuppeteerのインストールから動作確認までの流れは、以下のページの内容をそのまま試させていただきました。ありがとうございます。

HerokuにPuppeteerの実行環境を構築する - Qiita
HerokuにPuppeteerの実行環境を構築するはじめに本文は Node.js 2 Advent Calendar 2017 25日目の投稿です。またクリスマス直前で寂しく記事を書いていますが、皆さんの役に立つ情報であ...

新規プロジェクト、gitリポジトリの作成

はじめに新規プロジェクトのgitリポジトリを作成します。

プロジェクト名に「_(アンダーバー)」を入れると、場所は忘れましたが以降のどこかの手順でエラーになってやり直したので入れない方がよさそうです。
「-(ハイフン)」「英小文字」「数字」辺りが指定されていたように記憶しています。

% mkdir myapp
% cd myapp
% git init

package.jsonの作成

次にpackage.jsonを作成します。
「-y」オプションをつけることで対話形式をスキップしてpackage.jsonを一気に作成できます。

myapp% npm init -y
Wrote to /Users/{username}/develop/heroku/myapp/package.json:

{
  "name": "myapp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

Herokuプロジェクトの作成

myapp% heroku create myapp
Creating ⬢ myapp... done
Heroku | Welcome to your new app!
| https://git.heroku.com/myapp.git

Puppeteer用追加パッケージのインストール

ビルドパックを追加でインストールします。

Node.js。

myapp% heroku buildpacks:set heroku/nodejs
Buildpack set. Next release on myapp will use heroku/nodejs.
Run git push heroku main to create a new release using this buildpack.

Puppeteer用の追加パッケージ。

myapp% heroku buildpacks:add https://github.com/CoffeeAndCode/puppeteer-heroku-buildpack

Puppeteerをインストール

npmでpuppetterをインストール。バージョン15.4.0が入りました。

% npm i puppeteer
% npm list
└── puppeteer@15.4.0

Puppeteerの動作確認

Puppeteerをローカルで動かす

動作テスト用ファイルを作成します。
Puppetteerでスクレイピングするサンプルです。

myapp% vi puppeteer_demo.js 
const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('https://news.ycombinator.com', { waitUntil: 'networkidle2' });
  const newsTitles = await page.evaluate(() => {
    const elenemts = document.querySelectorAll('.itemlist .title > a');
    return [].map.call(elenemts, el => el.innerText);
  });
  console.log(newsTitles.slice(0, 5));
  await browser.close();
})();

実行すると無事スクレイピング結果を取得することができました。

myapp% node ./puppteer_demo.js 
[
  'Intel Microcode Decryptor',
  'Show HN: I made some ambient music generators that run in your browser',
  'Glassdoor not so anonymous',
  'To download from Google Drive, you must enable 3rd party cookies',
  'FCC: TikTok is unacceptable security risk and should be removed from app stores'
]

Puppeteerの動作確認はよさそうなので、次はブラウザからアクセスできるようにWebサーバーに仕立てます。
Webサーバーとして動かすために、nodeのWebアプリケーションフレームワーク「Koa.js」をインストールします。Expressがよく使われているようですが、参考サイトがKoa.jsを使っていたのでその通りに進めます。

koaと、ミドルウェア「koa-router」「koa-bodyparser」もインストールします。

$ npm i koa koa-router koa-bodyparser

最小限のWebサーバー機能とPuppeteerによるスクレイピング機能を持つWebサーバーを作成します。

const Koa = require('koa');
const Router = require('koa-router');
const bodyParser = require('koa-bodyparser');

const app = new Koa();
const router = new Router();

router.get('/', async (ctx, next) => {
  ctx.body = await crawler(); // クローラーの実行
});

app.use(router.routes());
app.use(router.allowedMethods());
app.use(bodyParser());
app.listen(process.env.PORT || 3000);

// ここからはクローラー(puppeteer_demo.js)のロジック
const puppeteer = require('puppeteer');
// Heroku環境かどうかの判断
const LAUNCH_OPTION = process.env.DYNO ? { args: ['--no-sandbox', '--disable-setuid-sandbox'] } : { headless: false };

const crawler = async () => {
  const browser = await puppeteer.launch(LAUNCH_OPTION); // Launch Optionの追加
  const page = await browser.newPage();
  await page.goto('https://news.ycombinator.com', { waitUntil: 'networkidle2' });
  const newsTitles = await page.evaluate(() => {
    const elenemts = document.querySelectorAll('.itemlist .title > a');
    return [].map.call(elenemts, el => el.innerText);
  });
  await browser.close();
  return newsTitles;
}

Webサーバーをローカルで実行して動作確認します。

% node ./index.js

ブラウザで、http://localhost:3000/にアクセスするとスクレイピング結果を取得できました。

PuppeteerをHerokuで動かす

Herokuアプリの起動時に、アプリで実行するコマンドを指定する Procfile​ が作成します。
Webサーバーなので種類は「web」です。workerの場合は「worker」になります。
Procfileは 拡張子なし です。つけると動作しないので注意。

% vi Procfile 
web: node index.js

gitにファイルをadd、commitし、herokuにpushします。
2、3分かかってpushが完了しました。

% git add .
% git commit -m 'init crawler'
% git push heroku main
〜
remote:  !     Warning: Your slug size (496 MB) exceeds our soft limit (300 MB) which may affect boot time.
remote:        Released v3
remote:        https://myapp.herokuapp.com/ deployed to Heroku
remote: 
remote: This app is using the Heroku-20 stack, however a newer stack is available.
remote: To upgrade to Heroku-22, see:
remote: https://devcenter.heroku.com/articles/upgrading-to-the-latest-stack
remote: 
remote: Verifying deploy... done.
To https://git.heroku.com/myapp.git
 * [new branch]      master -> master

動作確認します。

% heroku open

ブラウザが自動で起動して、HerokuにプッシュしたWebサーバーのページが表示されました。

2023.02.12追記

新しくHerokuアプリを作ると、最新のheroku-22になってうまく動かなかったので、ひとまず、以下コマンドで20にダウングレードすることで事なきを得ました。

heroku stack:set heroku-20 --app app-name

最後に

Node環境の構築からPuppeteerのインストール、Heroku環境へのデプロイ、ブラウザ動作確認までを行いました。ご参考になれば幸いです。

コメント

タイトルとURLをコピーしました