Seleniumとheadless chromeをAWS lambdaに入れてみました。（Win10環境下の注意点等）


Python でWeb Scraper を作る時に、対象ターゲットのがclient-side javascript で取得している際、単純にurlopenではほしい情報を取得できないことが多いです。そのため、SeleniumかAPI（もしあれば）で取得することが多いと思います。

一方で、定期的に、かつ経済的に何かを実行したい時には、on-demand のAWS lambdaとCloudEvent を使用するのが良いでしょう。

では、スタート

## 手順

### 環境構築

Windows環境下でAmazon LinuxをOSにしたAWS lambdaを使うには、**Ubuntu on Windows 10** かその他remote linux server の支援が必要です。今回はより経済的な方法として、Ubuntu on Windows 10 を選択。

具体的なインストール方法は以下参照すると良いでしょう。

[Windows 10でLinuxを使う](https://qiita.com/whim0321/items/093fd3bb2dd287a72fba)

次に、Pythonを入れておきます。

```shell
sudo apt-get update
sudo apt-get install python3.6
```


### 次

環境が整えたら、次にUbuntu 下で以下の操作を行う。

※Windowsで圧縮しても後にLambdaでエラー発生するので要注意。

- 分かりやすい場所に移動する、以下は例

  ```shell
　# Cディスクに移動する
  cd /mnt/c/  
  mkdir /path/to/folder
  cd /path/to/folder
  ```

  それで、File Explorerですぐに生成してファイルを見つけるでしょう。（あとでS3に入れる時が方便になります）

- headless chrome と chromedriver を取得

  - ここで注意すべきのは、新しいバージョンのheadless-chromiumを使っても、対応するchromedriverでないとエラー発生します。私が使っていたのは、以下の2つ
  - https://github.com/adieuadieu/serverless-chrome/releases/tag/v1.0.0-37  
  `stable-headless-chromium-64.0.3282.167-amazonlinux-2017-03.zip
`
  - https://chromedriver.storage.googleapis.com/index.html?path=2.37/
  `chromedriver_linux64.zip`

- 次に、それらを解凍して以下のように権限調整(`chmod 777`)して、最終的に以下のようにchromeフォルダーに格納し、1つのZIPファイルに圧縮します。

  ```
  chrome.zip
  chrome
  ├── chromedriver
  └── headless-chromium
  ```


- Ubuntu にselenium package のZIPファイルを作成する。

  

  ```shell
  mkdir python-selenium
  cd python-selenium
  
  python3 -m pip install --system --target ./ selenium
  zip -r python-selenium.zip ../python-selenium
  ```

- `chrome.zip`&`python-selenium.zip`をS3に入れて、Object URLをメモしておき、Layer作成しましょう。

- 最後サンプルを動いてみます。

  ```python
  from selenium import webdriver
  from selenium.webdriver.chrome.options import Options
  
  def lambda_handler(event, context):
      options = Options()

      # 自分の対応するファイルパスを入れる
      options.binary_location = '/opt/chrome/headless-chromium'
      options.add_argument('--headless')
      options.add_argument('--no-sandbox')
      options.add_argument('--single-process')
      options.add_argument('--disable-dev-shm-usage')

      # 自分の対応するファイルパスを入れる
      browser = webdriver.Chrome('/opt/chrome/chromedriver', chrome_options=options)
      browser.get('https://www.google.com')
      title = browser.title
      browser.close()
      browser.quit()
  
      return {"title": title}
  ```

  ここで注意するのは、Basic setting of lambda function（基礎設定）のところを、Exampleを動くにはメモリ消耗が256MB以上、Durationがおよそ10秒しました（512MB, timeout:20s設定の場合）、事前に調整して状況を見た方が良いでしょう。



### Q&A

もしかすると疑問ある方いるかもしれないので、いくつ自分がやる時に戸惑っていたことを書きます。

Q：なぜchrome フォルダーに入れて圧縮する

A：特に必要ないが、Lambdaにlayerを追加する際に、zipファイルにあるものを、`/opt`フォルダーにくっつきます。例えば、`/opt/chrome/chromedriver` & `/opt/chrome/headless-chromium`

Q：図示のように、Windows持っているzip化の使用はダメですか。

![image-20201008223558454.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/457921/0f709830-abd2-9a52-1f03-bef4d0c9304e.png)


A：実際にそれをLayerにアップロードすると、`Message: 'chromedriver' executable may have wrong permissions`というエラーメッセージが出されるので、調べたところ、どうも権限がうまくつけないらしい。そのため、Ubuntu下でファイルの権限調整し、圧縮しましょう。

## 参考

- [[Python] Headless Chrome を AWS Lambda で動かす](https://qiita.com/mishimay/items/afd7f247f101fbe25f30)
- [使用AWS Lambda 的“层 (Layer) ”功能实现依赖包管理](https://aws.amazon.com/cn/blogs/china/use-aws-lambda-layer-function/)


## おわりに
何かエラーを発生しても慌てずに、lambda test実行後のエラーレポートを確認すると良いでしょう。意外に問題点がはっきりと書いてある。