この記事の通り、Golang+Agouti+ChromeDriver+headless-chromeを使ってAWSLambda上で動かすことに失敗してしまったので、諦めてPythonを使用することにしました。
なお、こちらの方法はGolangで行う際より参考記事が豊富ですが、私自身Python自体も未経験でしたので、Pythonの使用手順から備忘録を兼ねて記載します。
Python実行環境
MacにはPythonが最初からインストールされていますが少々バージョンが古いようです。
バージョンはターミナルより確認できます。
$ python --version
私の場合2.7.10が入っていましたのでこれを3系に上げる必要がありました。
なおAWSLambdaのランタイムは最近で3.7、以前より3.6が対応していたようです。
Pythonのバージョンを上げるにあたり、pyenvを使用します(Rubyのrbenvに相当するやつでしょう、きっと)。
Homebrew経由で取得が可能です。
$ brew install pyenv $ pyenv -v
bashを追加します。
$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.bash_profile $ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.bash_profile $ echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
次にインストール可能なPythonのバージョンを検索します。
$ pyenv install --list
インストール可能なバージョンのものをインストールします。今回は3.6.5にしておきました。
$ pyenv install 3.6.5 $ pyenv versions system * 3.6.5 (...)
最後にpyenv経由でインストールしたPythonを設定して終了です。
$ pyenv global 3.6.5 $ python --version Python 3.6.5
AWSLambdaのデプロイパッケージ作成
デプロイパッケージにはGolangの際と同様にchromedriverとheadless-chromeが必要です。 取得方法は下記の記事をみてください。
それに加えSeleniumが必要になります。
Selenium取得
pip経由で取得が可能です。自力で行うとjarを実行するみたいな雰囲気がありましたが、その方法はGolang->Pythonと歩んでる最中の私には到底手を出す気になりませんでした。
任意のディレクトリ内で以下を実行します。
$ pip install selenium -t .
lambda-function.py
from selenium import webdriver def lambda_handler(event, context): options = webdriver.ChromeOptions() options.binary_location = "./headless-chromium" options.add_argument("--headless") options.add_argument("--no-sandbox") options.add_argument("--single-process") driver = webdriver.Chrome( executable_path="./chromedriver", chrome_options=options ) driver.get("https://hogehoge/accounts/login/") title = driver.title url = driver.current_url return title + url
一旦ページタイトルとURLを返却するのみのコードです。 chromeoptionなどはGolangの際と同様かと思います。
ただLambda上のハンドル名はPythonの場合「ファイル名.関数名」の為、lambda-function.lambda.handler
になります。
この部分がGolangの時と少々異なりました。
またzipをアップロードした場合はLambdaのコンソール上でコードが編集できるそうですが、S3にアップロードしてしまうとGolang同様できなくなります。
SPA対策
上記コードでSPAサイトのDOMを単純に触りに行くとElementが見つからず例外が発生します。対象のサイトはReact製でしたので、jsで生成されるDOMの対応を行う必要があります。
その際の対応策としてSeleniumのWebDriverWaitを使用します。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time def lambda_handler(event, context): options = webdriver.ChromeOptions() options.binary_location = "./headless-chromium" options.add_argument("--headless") options.add_argument("--no-sandbox") options.add_argument("--single-process") driver = webdriver.Chrome( executable_path="./chromedriver", chrome_options=options ) driver.get("https://hogehoge/accounts/login/") title = driver.title url = driver.current_url print(title) print(url) try: WebDriverWait(driver, 100).until(EC.presence_of_element_located((By.NAME, 'username'))) print("username is get") driver.find_element_by_name('username').send_keys('メールアドレス') print(driver.find_element_by_name('username').text) WebDriverWait(driver, 100).until(EC.presence_of_element_located((By.NAME, 'password'))) print("password is get") driver.find_element_by_name('password').send_keys('パスワード') print(driver.find_element_by_name('password').text) except TimeoutException as te: print(te) finally: driver.close() return title + url
他の手段としてはPhantomJSを使用することもできるそうですが、必要でなければWebDriverWaitで済ませてしまおうかと思います。
独学プログラマー Python言語の基本から仕事のやり方まで
- 作者: コーリー・アルソフ,清水川貴之監訳,清水川貴之,新木雅也
- 出版社/メーカー: 日経BP
- 発売日: 2018/02/24
- メディア: 単行本
- この商品を含むブログ (4件) を見る
- 作者: Bill Lubanovic,斎藤康毅,長尾高弘
- 出版社/メーカー: オライリージャパン
- 発売日: 2015/12/01
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (3件) を見る