ブラウザのコンソールログをSelenium(ヘッドレスブラウザ)で取得する

August 26, 2020

背景

NFS から s3 へデータを移行して WEB ホスティングするように基盤移行を行った際、404 のオブジェクトが多数発生していた。 また、s3 のオブジェクト名・プレフィックス名には禁則文字というものが存在するうらしい。 何が対象なのか判断するために、ブラウザのコンソールログを取得する必要があった。

動作環境

環境・ツール

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15.2
BuildVersion:   19C57

$ python3 -V
Python 3.7.3z

$ pip3 list | grep -e chrome -e selenium
chromedriver-binary 83.0.4103.39.0
selenium            3.141.0

install 手順

$ sudo pip3 install selenium
$ sudo pip3 install chromedriver-binary==83.0.4103.39.0

技術要素

  • selenium web driver
  • python
  • ec2

ファイル構成

./log/ (ログ出力先ディレクトリ)
./config.ini (設定ファイル)
./grep.py (実行ファイル)
./url.txt (検索対象のURLリスト)

実行準備

  • クローリング対象の URL を記載する
$ vi url.txt

http://user:password@google.com/
http://www.google.com/
...
  • config ファイルの配置
$ vi config.ini

[INTERVAL]
TIME_SEC = 5
[URL]
FILE = url.txt
[RESPONSE_CODE]
OK = 200
[LOG]
DIR = ./log/
TARGET = browser
LEVEL = SEVERE
TEXT_START = START
TEXT_DONE = DONE
  • 実行ファイルの配置
#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# selenium
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from selenium.webdriver.chrome.options import Options
import chromedriver_binary
# other modules
import re
import os
import signal
import datetime
import logging
import time
import configparser

# iniファイルの読み込み
conf = configparser.ConfigParser()
conf.read('config.ini', encoding='utf-8')

# ログ設定
logging.basicConfig(
  filename= conf['LOG'].get('DIR') + datetime.datetime.now().strftime('%Y%m%d_%H%M%S') + '.log',
  level=logging.INFO,
  format='%(asctime)s %(levelname)s %(message)s'
)

# chrome webdriver ログレベルの指定 ※オプション設定の影響を受ける
caps = DesiredCapabilities.CHROME
caps["goog:loggingPrefs"] = {conf['LOG'].get('TARGET'):conf['LOG'].get('LEVEL')}

# chrome オプション設定
options = Options()
options.add_argument('--headless') # ブラウザーのUIなしにする
options.add_argument('--ignore-certificate-errors') # SSL証明書失効サイト対策
# 他にも適宜オプション追加できる。mobileUIにするなど。

def main():
  try:
    logging.info(conf['LOG'].get('TEXT_START'))
    # Webdriver
    browser = webdriver.Chrome(desired_capabilities=caps,options=options)
    f = open(conf['URL'].get('FILE'))
    urlList = f.read()
    f.close()
    urls = urlList.split('\n')
    count = 1
    for url in urls:
      if len(url) == 0:
        logging.info(conf['LOG'].get('TEXT_DONE'))
        break
      else:
        # URLのステータスチェック
        status = requests.get(str(url))
        # 対象URL及びステータスのログ出力
        target_url_log = str(count) + ":" + str(status) + ":" + str(url)
        print(target_url_log)
        # ステータスコードが200の場合はINFO、それ以外はWARNINGでログ出力
        logging.info(target_url_log) if status.status_code == int(conf['RESPONSE_CODE'].get('OK')) else logging.warning(target_url_log)
        if status.status_code == int(conf['RESPONSE_CODE'].get('OK')):
          # 対象URLをブラウズし、指定したログを取得する
          browser.get(url)
          for _log in browser.get_log(conf['LOG'].get('TARGET')):
            print(_log)
            logging.warning(_log)

        count += 1
        # 負荷対策のためsleepをいれる
        time.sleep(int(conf['INTERVAL'].get('TIME_SEC')))
  except Exception as e:
    print(e)
    logging.error(e)
  finally:
    # chromedriver のプロセスが残ってしまうためkillする
    os.kill(browser.service.process.pid,signal.SIGTERM)

if __name__ == "__main__":
    main()

実行

$ python3 grep.py

2020-07-13 10:36:59,209 INFO START
2020-07-13 10:37:00,883 INFO 1:<Response [200]>:https://google.com/
2020-07-13 10:37:10,228 WARNING 2:<Response [404]>:https://google.com/aaa
2020-07-13 10:37:17,021 INFO 3:<Response [200]>:http://www.google.com/googlegooglegooglegooglegoogle...
2020-07-13 10:37:22,576 WARNING {'level': 'SEVERE', 'message': 'xxx', 'source': 'network', 'timestamp': 1594604239554}
2020-07-13 10:37:22,576 WARNING {'level': 'SEVERE', 'message': 'xxx', 'source': 'console-api', 'timestamp': 1594604239823}
2020-07-13 10:37:22,576 WARNING {'level': 'SEVERE', 'message': 'xxx', 'source': 'console-api', 'timestamp': 1594604241138}

tips

  • Chrome のバージョン(stable)と、python の chromedriver-binary のバージョンがうまく合わないと、うまく動いてくれません。

  • EC2(amazonlinux2)に chrome を入れる方法

## chrome install (yumは依存で詰まるからcurl)
$ curl https://intoli.com/install-google-chrome.sh | bash

## GConf2 リポジトリ追加 (ChromeDeiver動かすのに必要らしい)
$ sudo vim /etc/yum.repos.d/centos.repo

[CentOS-base]
name=CentOS-6 - Base
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=os
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6
#released updates
[CentOS-updates]
name=CentOS-6 - Updates
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=updates
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6
#additional packages that may be useful
[CentOS-extras]
name=CentOS-6 - Extras
mirrorlist=http://mirrorlist.centos.org/?release=6&arch=x86_64&repo=extras
gpgcheck=1
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6"
GPG key インポート rpm --import http://mirror.centos.org/centos/RPM-GPG-KEY-CentOS-6

## Google Noto Fontsいれる(キャプチャ取るわけじゃないから入れなくてもいいのかも)
$ Gconf2 install yum -y install GConf2
$ mkdir ~dl && cd dl
$ unzip Noto-hinted.zip
$ mkdir -p /usr/share/fonts/opentype/noto
$ cp *otf *ttf /usr/share/fonts/opentype/noto
$ fc-cache -f -v

### python3系いれる
$ sudo yum install python3
$ sudo pip3 update
$ sudo pip3 install --upgrade pip

###  利用しているchromeのバージョンと合わせる
# sudo pip3 install chromedriver-binary==84.0.4147.30
Nifty tech tag lists from Wouter Beeftink