Google Cloud上で定期的にスクレイピングを実施、結果をGoogleDirveに保存する方法をお伝えする講座の3回目です。
今回は、CloudFunctionを利用して実際にSeleniumを動作させる方法をお伝えします。言語はPythonとなります。
過去の講座はこちらより参照してください。
第2回「cloud schedulerによるジョブの定期実行方法」
スクレイピングに必要なツール・ライブラリ
スクレイピングを行うには、「Webブラウザ」、スクレイピング用ライブラリ「Selenium」、SeleniumとWebブラウザを結ぶ「Webドライバ」の3つが必要になります。
ただ、CloudFunctionには、「Webブラウザ」、「Selenium」、「Webドライバ」の3点は標準で設定されていないので、自分で設定する必要があります。
それぞれの設定方法をWEBサイトを調べると、様々な情報を取得することができますが、「Selenium」、「Webブラウザ」、「Webドライバ」のバージョンを合わせる必要があったり、利用している環境の前提が異なっていたりと、環境設定はかなり難易度が高く難しいです。
この講座では、有志の方がWeb上に取りまとめたスクレイピング用のパッケージ(「Selenium」、「Webブラウザ」、「Webドライバ」)を使うことで、CloudFunction上での環境設定を容易に可能としています。
スクレイピングの環境設定&デプロイ実行手順
設定手順を説明します。作業上のポイントや注意点は、後でまとめてお伝えします。
手順1 作業フォルダの作成と必要なファイルのダウンロード
まずは、GoogleCloud上にデプロイ用のファイル郡を格納するフォルダ「prj」を作成、スクレイピング用のパッケージをダウンロードし、フォルダ「prj」に「Selenium」、「Webブラウザ」、「Webドライバ」をコピーします。
CloudShellで以下のコマンドを打ち込めばOKです。
# HOMEフォルダにプロジェクト用のフォルダ「prj」を作成
mkdir prj
# スクレイピング用のパッケージをダウンロード
git clone https://github.com/ryfeus/gcf-packs.git
# ダウンロードしたパッケージのソースフォルダに移動
cd gcf-packs/selenium_chrome/source
# WEBブラウザがZIP圧縮されているので解凍
unzip headless-chromium.zip
# 「Selenium」、「Webブラウザ」、「Webドライバ」をプロジェクト用フォルダにコピー
cp chromedriver $HOME/prj
cp headless-chromium $HOME/prj
cp selenium $HOME/prj -r
手順2 ソースコード「main.py」の作成
次に、サンプルプログラムを作成します。お使いのPC上で「main.py」ファイルを作成、以下の内容を記載します。
プログラム自体は、「https://hobby.somnia.jp」アクセスして、タイトルを取得、ログに出力するものとなっています。
from selenium import webdriver
import os
def hello_pubsub(event, context):
# ブラウザーを起動
global driver
options = webdriver.ChromeOptions()
# 以下は各種オプションを設定 なくても動作するものがほとんどです
options.add_argument('--headless')
options.add_argument('--disable-gpu')
options.add_argument('--disable-extensions')
options.add_argument('--single-process')
options.add_argument('--proxy-server="direct://"')
options.add_argument('--proxy-bypass-list=*')
options.add_argument('--blink-settings=imagesEnabled=false')
options.add_argument('--lang=ja')
options.add_argument('--no-sandbox')
options.add_argument('--disable-dev-shm-usage')
options.add_argument("--log-level=3")
options.add_argument("--disable-logging")
options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36')
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option('useAutomationExtension', False)
options.page_load_strategy = 'eager'
# WEBブラウザとWEBドライバの場所を指定(GoogleCloudFunction用)
options.binary_location=os.getcwd()+"/headless-chromium"
driver = webdriver.Chrome(os.getcwd()+"/chromedriver",options=options)
# ↑2行をコメントアウトして以下1行に置き換えるとWindowsPC等他の環境でも動きます。
#driver = webdriver.Chrome(options=options)
# WEBページを取得
driver.get("https://hobby.somnia.jp")
driver.implicitly_wait(5) # 見つからないときは、10秒まで待つ
page_source = driver.page_source
# WEBページのタイトルを取得、7文字分表示
len=page_source.find("<title>")
print(page_source[len+7:len+14])
# ドライバのClose
driver.close()
driver.quit()
次に作成した「main.py」をGoogleCloud上の「prj」フォルダにアップロードします。
CloudShell画面右上のメニューよりアップロードを選択、開いた画面からファイルとアップロード先を設定し、下方の「アップロード」をクリックします。
これで必要なファイルの準備は整いました。
手順3 CloudFunctionへの登録
次は、CloudFunction上にプログラムを登録(デプロイ)します。
CloudShell のコンソールより以下のコマンドを実行してください。「prj-func」という名称のFunctionがデプロイされます。
cd $HOME/prj
gcloud functions deploy prj-func --trigger-topic=tenki --entry-point=hello_pubsub --runtime=python39 --region=us-west1 --memory=512MB --timeout=540 --set-env-vars TZ=Asia/Tokyo
コンソールにログインして初めてgcloudコマンドを実行した場合以下のメッセージがでるので「承認」をクリックします。
正しくデプロイできた場合以下のようになります。
CloudFunctionの画面に遷移すると、「prj-func」が登録されていることを確認できます。
こちらで登録作業は完了です。
スクレイピングの実行テストと動作確認
CloudFunctionのテスト実行機能を利用して、デプロイしたFunction「prj-func」の動作確認を行います。
今回のサンプルプログラムでは、取得したWEBページのタイトルをログに出力するので、テスト実行とその後のログ確認まで行い動作確認とします。
まずCloudFunctionの画面より「prj-func」をクリックします。
遷移した画面の中段あたりにある「テスト中」をクリック、その後画面が切り替わった後に、画面左下の「関数をテストする」をクリックします。これでテスト実行は完了です。
次にログの確認ですが、画面中段の「テスト中」の横の「ログ」をクリックすると、プログラムの実行ログが表示されます。
今回のサンプルが正しく動作した場合、ログに「ソムニア情報局」と表示されます。
なお、「ログ」をクリックするのが早いと、まだログが出力されていない時があります。その場合は少し待ってから再度「ログ」をクリックして下さい。
作業上のポイント・注意点
作業上のポイントや注意点、試行錯誤の中で分かったことを以下に記載します。
ブラウザ・Webドライバ・Seleniumはパッケージから取得すること
スクレピング用のパッケージ以外の「Webブラウザ」、「Selenium」、「Webドライバ」を利用すると、プログラムが動作しない場合があるので、注意してください。
1例ですが、CloudFucntionでは、requirements.txtというファイルに必要なPythonパッケージを記載することで、指定されたパッケージを自動で取り込む機能があります。
この機能で「Selenium」の最新版を取得して、CloudFunctionをデプロイしたのですが、プログラムが動きませんでした。
開発環境は別途準備すること
プログラムの開発・動作確認作業は、自分のPC上に構築しておくことをおすすめします。
私の場合、プログラムの「WEBブラウザ」、「WEBドライバ」を指定する部分を、実行環境によって変えております。
- GoogleCloudFunction用コード
# WEBブラウザとWEBドライバの場所を指定(GoogleCloudFunction用)
options.binary_location=os.getcwd()+"/headless-chromium"
driver = webdriver.Chrome(os.getcwd()+"/chromedriver",options=options)
CloudFunctionでは、自分で配置した「WEBブラウザ」、「WEBドライバ」を利用するため、os.getcwd()関数を使って保存したフォルダを指定します。
・開発環境用コード
driver = webdriver.Chrome(options=options)
自分のPC上であれば、事前に設定した「WEBブラウザ」、「WEBドライバ」を使うため、明示的にパスを指定する必要はありません。
CloudFunctionのPythonのバージョンは「3.9以下」にすること
CloudFunctionでは、Pythonのバージョンを選ぶことができます。記事を記載した時点では、「3.11」、「3.10」、「3.9」、「3.8」、「3.7」を選択できます。
ただし、今回の講座のプログラムは、Pythonのバージョン「3.11」、「3.10」では動きませんでした。「3.9」、「3.8」、「3.7」では動作することを確認しています。
なお、自分のPCでは「3.11」でプログラムが動作していることもあり、CloudFunction上のPythonのバージョンが限定されてしまうのは、スクレイピング用パッケージの問題ではないかと想定しております。
CloudFunctionのテスト実行は、実行時間が長くなる場合もあるので注意
CloudFunctionのテスト実行は、実行する時間帯によっては、プログラムの実行時間が長くなる場合があるようです。
手元でスクレイピングのプログラムを書いて実行しているのですが、スケジューラーによる定期実行であれば1分から2分程度で終わるプログラムが、テスト実行を行うと5分以上かかる時がありました。
要因調査をしたところ、WEB画面にアクセスする部分の処理に時間がかかっていました。テスト実行では、ネットワーク負荷の問題が発生して、処理パフォーマンスが落ちているのではと推察しています。
プログラム実行時間の長期化の原因は、ケースByケースで原因特定がしずらいですが、テスト実行でプログラムがタイムアウトしてしまう場合は、実行する時間帯を変えたり、スケジューラーから実行させてみましょう。
デプロイ時のメモリは512M以上を指定すること
CloudFunctionで指定できるメモリの最小値は256Mですが、WEBブラウザとしてChromeを起動するためか、256Mではメモリ不足でプログラムが動作しません。
スクレイピングを行う場合、CloudFunctionのメモリ設定を512M以上にしましょう。設定自体はデプロイ時に行います。
タイムゾーンの設定は忘れずに
CloudFunctionを実行するサーバーを海外にした場合、時間取得の関数を呼び出すと、そのサーバーの設置されている国の時間が返されます。
日本時間を取得したい場合は、デプロイ時にタイムゾーンを指定する必要があるのでご注意ください。
コマンド「gcloud functions deploy」の説明
デプロイ時に利用した コマンド「gcloud functions deploy」を説明します。
コマンドの構文は次の通りです。
gcloud functions deploy 【プロジェクト名】 【パラメータ】
プロジェクト名は任意の文字列を設定可能です。この講座では「prj-func」としています。
今回利用したパラメータは以下です。
パラメータ | 設定値 | 説明 |
–trigger-topic | tenki | Pub/Subで作成したトピック名 |
–entry-point | hello_pubsub | CloudFunctionが呼び出す関数名 変えた場合main.pyの関数も変えて下さい。 |
–runtime | python39 | Pythonのバージョン この場合3.9となります。 3.11の場合は「python311」と指定 |
–region | us-west1 | リージョン。 仮想マシンと同じにした |
–memory | 512MB | 最大メモリ |
–timeout | 540 | タイムアウト(秒) 第1世代CloudFunctionでは最大値540 |
–set-env-vars | TZ=Asia/Tokyo | タイムゾーンの設定 |
最後に
ここまでの手順を実行することで、第2回の講座で「Cloud Scheduler」に設定したジョブスケジュールに従って、CloudFunction「Prj-func」が自動実行される環境の構築が完了しました。
後は、「main.py」に本来実施したいスクレイピングの処理を実装して、都度デプロイを行うことで、スクレイピングを自由に制御できるようになります。
コメント