Dockerコンテナ上でPuppeteerの実装



# 1.はじめに
Webスクレイピングにおいて、用いるツールとして、Selenium, BeautifulSoupなど様々ありますが、JavaScriptにおいてはPuppeteerも代表的なスクレイピングツールとなっております。しかし、PuppeteerはローカルでChromium(google chromeやmicrosoft edgeも)を動かすことを想定されているので、Docker上での実行は少し複雑な手順を踏まなければならない


# 2.前提
### 2-1.puppeteer
今回はDockerを用いた記述方法なので、ローカルでpuppeteerを実行できていることを前提にします
### 2-2.Docker
Dockerにどれだけ慣れているかは問いません。しかし、Dockerの環境は準備できていることを前提にします。

# 3.実装
#### 3-1.ディレクトリ構造
```
practice
  ├─Dockerfile
  ├─docker-compose.yml
  └─index.js
```

### 3-2. index.jsの記述
今回は動作するかを確認するためだけに動かすだけなので、ただ開いて閉じるだけのコードを書きます。
まず、コードを書く前にターミナルで以下のコードを
```
npm install puppeteer
```
では、`index.js`に以下のコードを記述していきましょう

```javascript:indes.js
//puppeteerのインポート
const puppeteer = require("puppeteer");
(async () => {
//ブラウザの起動(ヘッドレスで)
  const browser = await puppeteer.launch({
    headless: true,
    slowMo: 10,
    defaultViewport: {
      width: 1000,
      height: 1000,
    },
    args: ["--lang=ja", "--no-sandbox", "--disable-extensions"],
  });

  try {
    const page = await browser.newPage();
    await page.setExtraHTTPHeaders({
      "Accept-Language": "ja-JP", //日本語版ページが読み込まれるようにする
    });
  } catch (e) {
    console.log(e);
  } finally {
//実行できたらブラウザを閉じて、コンソールに"done"と出力させる
    await browser.close();
    console.log("done");
  }
})();

```
記述後、ターミナルで以下を実行して`done`と出力されれば成功です。
```
node index.js
```

### 3-3.Dockerの記述
では、本題のDockerfileの記述についてですが、
先に結論から述べますと以下のファイルを実行するとうまくいきます。

```Dockerfile:Dockerfile
FROM node:18

RUN apt-get update \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \
    && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/* \
    && groupadd -r pptruser && useradd -rm -g pptruser -G audio,video pptruser

COPY ./ /usr/app
WORKDIR /usr/app


RUN node node_modules/puppeteer/install.js
RUN npm install puppeteer --save-dev --unsafe-perm=true --allow-root

RUN npm install

CMD ["google-chrome-stable"]
```

そして、実行にはdocker-composeを用いたいので`docker-compose.yml`には以下を記述します。
```yaml:docker-compose.yml
services:
  app:
    build: .

    tty: true
    ports:
      - "80:80"
    volumes:
      - ./:/usr/src/app
    command: >
      bash -c "npm install &&
      node index.js"
```

記入後、以下のコマンドをターミナルで起動します。`done`と出れば成功です。
```bash
$ docker-compose up
```

#### 解説
まず、Docker上でヘッドレスなChromeを起動して実行するのは結構難しいそうです(笑)<-公式が明言
その理由としては、puppeteer経由でとってくるchromiumには**必要なライブラリが入っていない**らしいです
そのため、必要なライブラリをとってくる必要があり、`Dockerfile`の3行目以下のコードが必要となってきます👇
```dockerfile:Dockerfileの3行目
RUN apt-get update \
    && apt-get install -y wget gnupg \
    && wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/googlechrome-linux-keyring.gpg \
    && sh -c 'echo "deb [arch=amd64 signed-by=/usr/share/keyrings/googlechrome-linux-keyring.gpg] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
    && apt-get update \
    && apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-khmeros fonts-kacst fonts-freefont-ttf libxss1 \
      --no-install-recommends \
    && rm -rf /var/lib/apt/lists/* \
    && groupadd -r pptruser && useradd -rm -g pptruser -G audio,video pptruser
```

# おわりに
いかがでしたでしょうか？
Docker上でのpuppeteerでは新しいchromeのイメージを作る必要がありました。しかも、素直に作ろうとすると起動できない仕様でした。
Dockerでのスクレイピングができるようになればより、ウェブアプリ開発の幅が広がると思います。

説明が至らぬ点も多かったと思いますが少しでも助けになれば幸いです。今後ともよろしくお願いします。

### 参考
puppeteerのドキュメント:  https://pptr.dev/guides/docker/