
AWS Lambda でWebスクレイピングできなかったサイトについて
ちょっと前に書いた以下のWebスクレイピングの記事に関してですが、結局AWS Lambdaでは動かすことができず、EC2で妥協したサイトが2種類ほどありましたので、情報を残しておきたいと思います。
メール認証が必要なサイト
ユーザー名とパスワードの認証が終わった後にSMSやメールに認証コードが送られてきて、それを入力しなければならないため、AWS Lambdaで動作させることは難しいと判断しました。Lambdaは毎回違うインスタンスが立ち上がるためパスワードを記憶させることは出来ないという結論に至りました。
キャプチャ認証が必要なサイト
seleniumでキャプチャ認証を突破する有料サービスはあるのですが、セキュリティ面と手間がかかることを考慮してLambdaで動かすことは断念しました。
キャプチャ認証を突破する方法は以下のサイトが分かりやすいと思います。
EC2で動作させるためのノウハウ
今回、自動化を難しくしているサイトの特徴として、ログイン認証が複雑なことがネックになることが分かりました。EC2ではLambdaとは違いGUIでブラウザのウィンドウを立ち上げてWebスクレイピングすることができますので、このGUIを初回だけ人が操作して認証を突破し、パスワードを記憶させて、2回目以降は認証なしでサイトにアクセス出来るようにしました。
パスワードをブラウザに記憶させるコツですが、初回用に以下のようなPythonプログラムを作って対応します。ログインページにアクセスした後、長時間スリープさせておいて、その間に各種の認証を突破します。
try: import unzip_requirements except ImportError: pass import sys import os import time import calendar import datetime import logging import subprocess import post_to_chatwork import boto3 import shutil from glob import glob from pathlib import Path from bs4 import BeautifulSoup from selenium import webdriver from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import Select from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.common.action_chains import ActionChains from selenium.webdriver.support.ui import Select mode2bucket = { 'dev': 'sample-scraping-dev-us-east-1', 'pro': 'sample-scraping' } def post_to_chat(title, body): ptc = post_to_chatwork.PostToChatwork(title, body) ptc.post_to_chatwork() del ptc def main(event, context): print("main start") # レベル logger = logging.getLogger() logger.setLevel(logging.INFO) STAGE = os.environ['selected_stage'] print("stage[%s]" % STAGE) MODE = os.environ['scraping_mode'] print("mode[%s]" % MODE) prog_name = os.path.splitext(os.path.basename(__file__))[0] if context: print("start lambda_handler() [%s]" % context.function_name) #today d = datetime.datetime.today() #yesterday d2 = d - datetime.timedelta(days=1) target_url = 'https://sample.sample/' user_id = 'sample@sample.sample' password = os.environ['user_password'] try: options = webdriver.ChromeOptions() options.binary_location = "/opt/google/chrome/chrome" # options.add_argument("--headless") # options.add_argument("--disable-gpu") # options.add_argument("--window-size=1280x1696") # options.add_argument("--disable-application-cache") # options.add_argument("--disable-infobars") # options.add_argument("--no-sandbox") # options.add_argument("--hide-scrollbars") # options.add_argument("--enable-logging") # options.add_argument("--log-level=0") # options.add_argument("--single-process") # options.add_argument("--ignore-certificate-errors") options.add_argument("--homedir=/tmp") options.add_argument("--user-data-dir=/home/ubuntu/.config/google-chrome/Default") driver = webdriver.Chrome(options=options, executable_path='./bin/chromedriver') driver.command_executor._commands["send_command"] = ( "POST", '/session/$sessionId/chromium/send_command' ) params = { 'cmd': 'Page.setDownloadBehavior', 'params': { 'behavior': 'allow', 'downloadPath': '/tmp' } } driver.execute("send_command", params=params) driver.implicitly_wait(10) driver.get(target_url) # login print("before log in") # driver.find_element_by_name("rememberMe").click() # driver.find_element_by_id("email").send_keys(user_id) # driver.find_element_by_id("password").send_keys(password) # driver.find_element_by_id("signIn").click() print("after log in") print(driver.current_url) time.sleep(1000) # 手動による認証が終わったらCtrl+Cなどでプロセスを終了させる
- ヘッドレスchromeから普通の画面ありchromeに変更したため、options.binary_locationのパスを修正しました。
- options.add_argument(“–headless”)以下のオプションは画面ありchromeで不要なため、削除しています。
- パスワードを記憶させたいため、ユーザー情報保持用のディレクトリをoptions.add_argument(“–user-data-dir=??”)で指定しています。
まとめ
この2種類のサイトについては、もしREST APIが公開されていれば、使用して自動化も簡単にできたと思うのですが、残念ながら現状存在しませんでした。是非とも公開してもらえるとありがたいなぁと思う今日この頃です。

優秀な技術者と一緒に、好きな場所で働きませんか
株式会社もばらぶでは、優秀で意欲に溢れる方を常に求めています。働く場所は自由、働く時間も柔軟に選択可能です。
現在、以下の職種を募集中です。ご興味のある方は、リンク先をご参照下さい。