Google Cloud Functionsを使って、スクレイピングを自動化したい
この記事に書いてあるとおり、過去にお名前VPSを使ってFXの自動取引を行なっていました。
全ての取引を自動化 前々からFXを自動取引してみたいな~という気持ちはありつつ、 そもそもEA(エキスパートアドバイザー)を作るハードルや、金銭的な余裕がなかったので手は出していませんでした。 普通にEAを買おうとすると安くて[…]
で、もうFXの自動取引はやっていないわけですが、TwitterのBotとか、仮想通貨取引のレート取得のために、そのVPSを使ってスクレイピングを定期実行していました。
そんなしょうもないことに毎月1,300円払うのも馬鹿らしくなったので、思い切ってお名前VPSを解約して、少しずつGoogle Cloud Functions(以下GCF)に移行してました。
GCFでの定期実行に関しては参考になる記事がたくさんあったので、つまずき続けながらも、なんとか前に進むことができました。
以下、参考になった記事たち。
- サーバーレス + Pythonで定期的にスクレイピングを行う方法
- Cloud SchedulerとCloud Functionsを使って自動スクレイピングさせて、スプレッドシートに書き出してみた(Python)
- ローカルでのスクレイピング作業をGCPに持っていく作戦(その1)
幾多ものつまずきの中で2つ紹介します。
つまずきポイント①:引数の指定
import os
def Hoge(event, context): #ココ
fuga = 1
def Hoge():
となっていて、引数がなにも設定されていませんでした。
でも仕様変更?があったのか、引数にevent, contextが設定されていないとダメっぽい。細かい仕様は分からんのですが。(分かる人いたら教えて)
ちなみに誤ってeventではなくdataという引数を設定してしまったんですが、きちんと動作したので別に引数の指定はなんでもいいっぽいです。
つまずきポイント②:BigQuery・スプレッドシートとの連携
BigQueryにデータを保存して、そのデータを元にGoogle Data Studioでビジュアライズすることを目指していました。
GCFからBigQueryの書き込みは割と簡単で、pandasでできます。
df.to_gbq(table_id, project_id,if_exists='append')
で、加えてスプレッドシートにも書き込みをしようと思ったのですが、その際の認証周りがよく分からず。
お名前VPSで動かしていたときはjsonのキーファイルを読み込んで認証していたのですが、そのjsonキーファイルをGCFでどう読み込めば良いのか分からなかった。
Cloud Storageにいれても上手くパスを読み込めないし、いろいろな記事を読んでも「認証をウンタラカンタラ」ばかりで、その「認証をウンタラカンタラ」ができませんでした。
最終的に海外の記事で、とんでもない方法でやっていた人がいたので、そちらを参考にしました。
具体的には、こんな感じ。
def bq_insert(event, context):
#ここはBigqueryへの書き込み
df = pandas.DataFrame(data=df_list, columns=columns)
project_id = 'PROJECT-ID'
table_id = 'TABLE-ID'
df.to_gbq(table_id, project_id,if_exists='append')
#ここからスプレッドシートへの書き込み
scopes = [
'https://www.googleapis.com/auth/spreadsheets',
'https://www.googleapis.com/auth/drive'
]
json_data = {
'type': 'service_account",
'project_id': "hogehoge",
'private_key_id': "fugafufa",
'private_key': '-----BEGIN PRIVATE KEY-----hogehogehoge,
'client_id': 'CLIENT-ID',
'auth_uri': 'https://accounts.google.com/o/oauth2/auth',
'token_uri': 'https://oauth2.googleapis.com/token',
'auth_provider_x509_cert_url': "https://www.googleapis.com/oauth2/v1/certs',
'client_x509_cert_url': "https://www.googleapis.com/robot/v1/metadata/abababababab'
}
credentials = ServiceAccountCredentials.from_json_keyfile_dict(json_data, scopes)
gc = gspread.authorize(credentials)
JSONデータを、直接コードに書き込んじゃうという荒業w
セキュリティ的な問題とかあるのかな?そのへんはよく分からんけども。
Google Cloud FunctionsでSeleniumを動かしたい
で、本題です。
Selenium + WebDriverの実装で詰んだ
- GoogleCloudFunctionsでSeleniumを使う
- Google Cloud FunctionsのPythonランタイムでChrome + Seleniumを利用する
- 【コード付!?】Cloud Functions x Seleniumを徹底解説
def Hoge():
def Fuga(request):
PhantomJSCloudで、Seleniumの代用をする
SeleniumでもPhantomJSは動かせますが、PhantomJSCloudはリクエストしたURLをPhantomJSCloudがスクレイピングして値を返してくれるものです。
なので問題だったドライバーをインストールが、PhantomJSCloudでは必要がありませんでした!!
payload = {'url':'https://google.com/','renderType':'HTML','outputAsJson':'true'}
payload = json.dumps(payload)
payload = urllib.parse.quote(payload, safe = '')
phantomjs_key = 'API-KEY'
url = 'https://phantomjscloud.com/api/browser/v2/' + phantomjs_key + '/?request=' + payload
pj_res = requests.get(url)
pj_res = pj_res.json()
html = pj_res["content"]["data"]
soup = BeautifulSoup(html, 'html.parser')
まとめ
Google Cloud FunctionsでSelenium使うより、PhantomJSCloud使ったほうが良さそう。
GCF×Seleniumで無駄にした時間=5時間くらい
PhantomJSCloudに切り替えて実装した時間=10分