reCAPTCHAのサイトを毎日自動スクレイピングする (6/7: コンテナ化)

1. [要件定義〜python環境構築](https://qiita.com/kamyu1201@github/items/65a86ec1e28ec9969dcb)
1. [サイトのスクレイピング機構を作る](https://qiita.com/kamyu1201@github/items/a07c7d175c051b8ab4c0)
1. [ダウンロードしたファイル(xls)を加工し、最終成果物(csv)を作成するようにする](https://qiita.com/kamyu1201@github/items/925337a317dec3c6f5d0)
1. [S3からのファイルダウンロード / S3へのファイルアップロードをつくる](https://qiita.com/kamyu1201@github/items/078a9c6239811998843e)
1. [2captchaを実装](https://qiita.com/kamyu1201@github/items/d3daada504c76e601f6e)
1. **Dockerコンテナで起動できるようにする**
1. AWS batchに登録


# サーバ上で動くようにする

前回までで、一度起動させれば、あとは何もせず自動で動くようになりました。
cronでも設定すれば毎日の実行でもできますが、このままだと 自分のPCをずっと起動させることになってしまいます。
なんとかサーバ上で起動するようにしたいところです。

ここで壁になるのが、**今回のスクレイピングは、Displayが必須になること**。
Chromeのheadlessモードなども試したのですが、うまくいきませんでした。

というわけで今回は、少し古い技術ではあるものの`Xvfb`という仮想ディスプレイを作成できる仕組みを使って実装することに。

Xvfbは、Linux上で動くアプリケーションです。
ので、LinuxのDockerコンテナを使って実装し、最終的に AWS batchを使ってバッチ実行する方針でいくことにしました。


# Docker image作成

### 作成のための検証

※Dockerのダウンロードやインストールは割愛します

まずは、自分の使う`Docker image`を作っていきます。
Xvfbを調べていたら利用実績が多そうだった、CentOSを使っていきます。

まずは既存のcentOS imageから起動させ、必要なアプリケーションを実際にインストールしてみます。

```bash:mac(host)
docker pull centos          #DockerHubからcentOSのimageを引っ張ってくる
docker run -it -d centos    #起動させる
docker ps                   #起動を確認&コンテナIDを取得
docker exec -it b7948c7802eb /bin/bash  #コンテナ側のターミナルに入る
```

必要なのは

- python
- pythonパッケージそれぞれ
- Xvfb
- firefox

なのでそれぞれインストールしてみます。

```bash:container内でいろいろ試す
yum install -y python36 #python入れる
python3 -m pip install --upgrade pip #pip入れる
pip install requests #必要なパッケージ入れてみる
...
yum -y install xorg-x11-server-Xvfb  #Xvfbのインストール
yum -y install firefox  #firefoxのインストール
Xvfb :1 -screen 0 1600x1200x16 & #Xvfbの起動
export DISPLAY=:1 #:1と定義したディスプレイを使う
firefox #firefoxを起動
```

お。画面がよく見えないのですが、firefox起動してるぽい…？
というわけで次は、ここで自分のプログラムを実行させてみます。

ここで私はDockerfileの作成に入りました。
本当は`docker cp`コマンドとかを使って入れてみて試すほうが効率がいいのかも。


### Dockerfileの作成

```bash
FROM centos
ENV TZ JST-9  #(1)

#ホームディレクトリを設定
ENV HOME=/home
WORKDIR $HOME

#自分のアプリ(app以下)をhome以下に移す
COPY .  $HOME/

RUN yum install -y python36
RUN python3 -m pip install --upgrade pip
RUN pip install -r app/requirements.txt #(2)
RUN yum -y install xorg-x11-server-Xvfb
RUN yum -y install firefox

RUN chmod 744 startup.sh
CMD ["./startup.sh"]  #(3)
```

(1) どうやらタイムゾーンはUTCになってしまう模様。今回のバッチは時間が重要なのでタイムゾーンを変更しています
(2) 最初は一行ずつ書いていたのですが、まとめたほうがきれいだったのでrequirements.txtに必要パッケージをまとめました。必要パッケージは`pip freeze`コマンドで出てきたものをそのまま記載。
(3) Xvfbの起動コマンドは、`docker run`のタイミングですることが必要だとわかったので、shellを作成してまとめました。

```bash:startup.sh
#!/usr/bin/env bash
Xvfb :1 -screen 0 1600x1200x16 &
export DISPLAY=:1
python3 app/source/run.py --run_mode test #最後はnormalにするが
```

### linuxで動くために少々変更

- geckodriverはlinux用のものをダウンロード
- OSを判断し、どのdriverを使うのか、で分岐するように変更


最終的なファイル構成はこうなります。

```
├── Dockerfile
├── README.md
├── app
│   ├── drivers
│   │   ├── geckodriver
│   │   └── geckodriver_linux
│   ├── requirements.txt
│   └── source
│       ├── run.py
│       ├── scraping.py
│       ├── make_outputs.py
│       ├── s3_operator.py
│       └── configs.py
├── startup.sh
└── tmp
    ├── files
    │   ├── download
    │   ├── fromS3
    │   └── toS3
    └── logs
```


# 起動してみる

下記のコマンドで実行できます。

```bash
docker build -t myapp .
docker run -it myapp
```

本当はこんなスラスラといかなかったですけどね…。上のコマンドは40回くらい打った気がします。

しかし、うまく行ったときは感動モノです！
画面は全く見えないけど、コンソールは出ているし、S3にファイルができているのですから。


最後は、AWS上で実行させるだけ…。ゴールが見えてきました。