さくらVPSにPython+Selenium+GoogleChromeを入れて実行する

Chromeを起動してWEBページにアクセスし、スクレイピングするために色々やった備忘録です。
・ドライバーは自動で更新したい
・後々APIにする予定なのでHTTPでアクセスできるようにする（SSL化も）

まとめるために何度かやったんですが1回でうまくいった試しがありません。
とにかくエラー出たら落ち着いて確認。

# 環境
さくらVPS
ubuntu 18.04 and64

# Pythonのインストール
Pythonを入れるために[pyenv](https://github.com/pyenv/pyenv)をインストールします。
いらない場合は飛ばしてください。

## pyenvをインストール
まずは依存パッケージをインストールします。
githubに必要なパッケージがOS毎にかかれているのでコピペ。
https://github.com/pyenv/pyenv/wiki

```ssh
sudo apt update
sudo apt install make build-essential libssl-dev zlib1g-dev \
libbz2-dev libreadline-dev libsqlite3-dev wget curl llvm \
libncursesw5-dev xz-utils tk-dev libxml2-dev libxmlsec1-dev libffi-dev liblzma-dev
```

gitをインストール
```ssh
sudo apt install git
```

pyenvをクローン
```ssh
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
```

PATHを設定
```ssh
echo 'export PATH="$HOME/.pyenv/bin:$PATH"' >> ~/.bash_profile
echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
source ~/.bash_profile
```

インストール出来ればバージョンが表示されます
```ssh
pyenv -v
```

## Pythonのインストール
`install --list`でインストール可能なバージョンが表示されるので、入れたいバージョンを指定してインストールします。
今回は3.11.0にしました。
```ssh
pyenv install --list
pyenv install 3.11.0
```

バージョンを切り替えます
```ssh
pyenv global 3.11.0
pyenv rehash
python --version
```

# Google Chromeのインストール
パッケージリストに追加
```ssh
sudo sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
```

追加されたか確認
```ssh
ls -l /etc/apt/sources.list.d
cat /etc/apt/sources.list.d/google.list
```

公開鍵をDLしてapt-keyで登録する
```ssh
sudo wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
```

パッケージリストを最新の状態に
```ssh
sudo apt update
```

パッケージを確認する
```ssh
apt list google*
```

インストールします。
今回はstableを入れました。
```ssh
sudo apt-get install google-chrome-stable
```

インストール出来ればバージョンが表示されます。
```ssh
google-chrome --version
```

# ライブラリをインストール
まずはpipをアップグレードします
```ssh
pip install --upgrade pip
```

ライブラリをインストール
```ssh
pip install selenium
pip install webdriver_manager
```

chromedriver_binaryをインストールしようとするとエラーが出る…
```--use-pep517```を付けないとダメらしい
https://github.com/pypa/pip/issues/8559
```ssh
pip install --use-pep517 chromedriver_binary
```

バージョン確認
```ssh
pip show [モジュール名]
```

# ドライバーの自動更新
chromedriverは定期的にアップデートする必要があるため、プログラムの起動時に自動でアップデートするよう設定します。

```python:example.py
from selenium import webdriver
from selenium.webdriver.chrome.service import Service as ChromeService
from webdriver_manager.chrome import ChromeDriverManager

# chromeを起動
options = webdriver.ChromeOptions()
options.add_argument('--headless')
browser = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()), options=options)
# URLにアクセス
browser.get('https://～')
```

とりあえずここまででスクレイピングするための準備は出来ました。
あとはひたすらコード書けばOK。
私はcrontabで定期実行するようにしています。

# crontabを設定
```ssh
crontab -e
0 15 * * * /home/ubuntu/.pyenv/shims/python3.11 /home/ubuntu/var/www/html/example.py
# 確認
crontab -l
```
pyenvの中のpythonから実行するように設定します。
パスはご自身の環境に合わせてください。

ここから下はおまけです。

# HTTPでアクセスできるようにする
## NGINXをインストール
```ssh
sudo apt install nginx
```

インストールされたか確認
```ssh
nginx -v
```

公開ディレクトリを作成、index.htmlを作成します。
先ほどのexample.pyを置いたのもここです。
```ssh
sudo mkdir var
sudo mkdir var/www
sudo mkdir var/www/html
# index.htmlを作成
sudo vi var/www/html/index.html
```
```html:var/www/html/index.html
Hello!
```

先ほど作成したディレクトリを公開設定
```ssh
sudo vi /etc/nginx/sites-available/default
```
```ssh:/etc/nginx/sites-available/default
...
root /home/ubuntu/var/www/html; # 追加
```

再起動します
```ssh
sudo systemctl restart nginx
```

ブラウザでアクセスして「Hello!」と表示されればOK

# Let's EncryptでSSL化
Let's Encryptをインストール
```ssh
sudo apt install certbot python3-certbot-nginx
```

ドメイン設定します。
メールアドレス、ニュース等のお知らせを受け取るか、非SSLでのアクセスからリダイレクトするかを聞かれるので入力。
```ssh
sudo certbot --nginx -d [ドメイン]
```

更新タイマーの確認
```ssh
sudo systemctl status certbot.timer
```

![スクリーンショット 2022-11-28 124841.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308640/1f9ae72e-18f9-1e0e-88c4-6ac61cacbbc9.png)

更新のテスト
```ssh
sudo certbot renew --dry-run
```

pemファイルが生成されれば成功です。
![スクリーンショット 2022-11-28 125230.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308640/05666e89-f8aa-9734-075d-c048bfc2c800.png)

## NGINXでポート443の設定
```ssh
sudo vi /etc/nginx/sites-available/default
```
```ssh:/etc/nginx/sites-available/default
...
root /home/ubuntu/var/www/html; # 443の中に追加
```

## パケットフィルターを設定
さくらVPSのコントロールパネルからパケットフィルターの設定をします。
「Web」を指定すると80/443ポートが追加されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/308640/58d88254-1f62-feff-5b3f-3f62751afb74.png)

## PHPをインストール
API化のためPHPも入れます。
このままだとPHP7.2までしか入れられないのでレポジストリを追加します。
```ssh
sudo apt install software-properties-common
sudo add-apt-repository ppa:ondrej/php
```

aptを最新の状態に
```ssh
sudo apt update
```

パッケージを確認する
```ssh
apt list php*
```

PHP本体と必要なモジュールをインストールします。
今回は7.4で。
```ssh
sudo apt install php7.4 php7.4-fpm php7.4-mbstring php7.4-zip
```

確認
```ssh
php -v
```

このままだとアクセスしても実行されないので設定します。
```ssh
sudo vi /etc/nginx/sites-available/default
```

```ssh:/etc/nginx/sites-available/default
location \ {
    ...
    index index.php index.html index.htm;

location ~ \.php$ {
    ...
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
```

再起動
```ssh
sudo systemctl restart nginx
```

# Dockerで開発環境を作る
開発はローカルで、本番環境と同じ環境でやりたい。だってその方が楽だから。
そんなわけで、なるべくローカルの環境は汚さずに、本番環境と同じように動かせる環境をDockerで作ってみました。

OSはWindows11 Pro、Docker Desktopインストール済みです。

```text:Dockerfile
# python
FROM python:3.11
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN mkdir -p /root/app/
COPY requirements.txt /root/app/
WORKDIR /root/app/

RUN sh -c 'echo "deb http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
RUN wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -
RUN apt update
RUN apt-get -y install google-chrome-stable

RUN pip install --upgrade pip
RUN pip install --upgrade setuptools
RUN pip install -r requirements.txt
```

```yml:docker-compose.yml
version: '3'

services:
  python3:
    image: python:3.11
    build: .
    container_name: python3
    working_dir: /root/app/
    volumes:
     - ./src:/root/app/
    restart: always
    tty: true
```

```text:requirements.txt
requests
numpy
pandas
selenium
webdriver_manager
chromedriver_binary
```

requirements.txtにはpipでインストールしたいモジュール名を書いておきます。

ファイル構成はこんな感じです。
srcディレクトリ内に実行したいファイルを入れます。

```
docker-python/
  src/
  Dockerfile
  docker-compose.yml
  requirements.txt
```

ファイルを作成したらコマンドで以下を実行します。
buildに時間がかかるので気長に待ちます。

```shell
cd docker-python
docker compose build # 必要なものをインストールする
docker compose up -d # コンテナ起動
docker compose exec python3 bash # コンテナに入る
```

余談ですが、Windows10時代にWSL2を入れようとして上手くいかなかったのに、11にしたらあっさり上手くいったんですよね。何でだろう。