株式会社シナプス技術部ネットワーク課の杉原です。
これから、Linux の CUI 環境で Google Chromeを動かす方法についてご説明いたします。
GUI と CUI について
GUI(Graphical User Interface)
GUIとは、画面上に視覚的な画像や図形が用いられているインターフェイスのことです。
キーボードとマウスを使って画面上のテキストフォームやボタンなどのパーツを動かすことで、プログラムを実行します。
普段、みなさんが使っているPCやスマートフォンの画面がGUIにあたります。

CUI(Character User Interface)
CUIは画面上に文字情報のみが表示されるインターフェイスのことです。
マウスを使わずキーボードでコマンドラインを入力することで操作を行います。
現在、ネットワーク装置やUNIX系サーバーはCUIでの操作が主流になってます。

では、CUIの環境でWebページを閲覧できるのでしょうか?
結論から言うと、可能です。
実は皆さんの普段つかっているWebブラウザはCUI環境でもインストールして実行することができます。
ということで、今回は CentOS8 に Google Chrome をインストールしてみます。
CentOS8 への Google Chrome のインストール方法
1. vi コマンドで、/etc/yum.repos.d/google.chrome.repo を開き以下のように記述します。
$ vi /etc/yum.repos.d/google.chrome.repo --------------------------------------------------------------- [google-chrome] name=google-chrome baseurl=http://dl.google.com/linux/chrome/rpm/stable/$basearch enabled=1 gpgcheck=1 gpgkey=https://dl-ssl.google.com/linux/linux_signing_key.pub ---------------------------------------------------------------
2. dnf コマンドでインストールします。
$ dnf install google-chrome
これで、Google Chromeのインストールは完了です。
Linux で Google Chrome を実行する方法は大きく分けて以下の二種類があります。
- ヘッドレスモードでGoogle Chromeを実行する
- Seleniumを使用する
それでは、それぞれの方法を見ていきたいと思います。
1. ヘッドレスモードでGoogle Chromeを実行する
Google Chrome にはヘッドレスモードと呼ばれる、CUI上でブラウザを起動できるモードがあります。
以下のコマンドで、指定したURLのWebページのスクリーンショット画像を取得できます。PNG方式にのみ対応しています。
$ google-chrome --no-sandbox --headless --disable-gpu --screenshot="screenshot_$(date +"%Y%m%d").png" --window-size=1280,1080 https://www.synapse.jp/
また、以下のコマンドで、指定したURLのWebページのスクリーンショットをPDF形式で保存できます。
$ google-chrome --no-sandbox --headless --disable-gpu --print-to-pdf="test.pdf" --user-data-dir="./" https://www.synapse.jp/
※mac から行う場合はalias google-chrome='/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chromeを事前に実行するようにzshに設定してください。
2. Seleniumを使う
Seleniumは、Webブラウザの自動テストを行うためのライブラリです。
Webページを開発した後、「ボタンが押されたらアラートが正しく表示されるか」「リンクをクリックすると指定したページにジャンプするか」といった事柄を検証するときに、変更点があるたびにポチポチクリックするのではなく、自動的に実行できたら楽になるはずです。
Seleniumを導入すると、プログラムのソースコードに「テキストフォームに文字を入力する」「セレクトボタンを選択する」「送信ボタンを押す」などの処理を書くことで、それらの処理を自動的に実行できるようになります。
Python, JavaScript, Ruby, C# , Kotlinなどのプログラミング言語に対応しています。
Python3 への Selenium のインストール方法
ここからは Python3 を前提に Selenium の導入を説明します。
1. まずは、Selenium をインストールします。
pip install selenium
2. インストールされている Google Chrome のバージョンを確認します。
$ google-chrome --version Google Chrome 90.0.4430.93
3. Google Chrome のバージョンと同じバージョンのバイナリドライバをインストールします。
pip install chromedriver_binary==90.*
これで、各種ライブラリのインストールは完了です。
それでは、PythonとSeleniumを使って、シナプスの公式ホームページを操作してみようと思います。
(1)シナプスHPトップのMBCニュースと南日本新聞の見出しを取得する。
シナプスHPトップのMBCニュースと南日本新聞の見出しを取得し、コマンドライン上に表示したいと思います。
注意
ここで行うWebページ上の文字の自動取得はスクレイピングとよばれ、サイトによっては禁止されていることがあるのでご注意ください。
また、今後、シナプスのホームページのデザインや構成が変わる可能性がございますので、ご留意ください。
シナプスのHP(https://www.synapse.jp/)にアクセスして、検証機能を使って操作箇所のタグを確認します。

MBCニュースのタブは id=tab1 、南日本新聞のタブは id=tab2 の要素のaタグが割り当てられています。
MBCニュースの見出しは id=nbox1 のdivタグの中でliタグを使って列挙されていることがわかります。
南日本新聞の見出しは id=nbox2 のdivタグの中でliタグを使って列挙されていることがわかります。
それを踏まえた上で、以下のようにコードを記述します。
from selenium import webdriver
import chromedriver_binary
# ドライバーの準備
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(options=options)
# 対象のURLを指定
driver.get("https://www.synapse.jp/")
# ウィンドウサイズを指定
driver.set_window_size(1200, 720)
# (1) 最初に訪れた時点でのスクリーンショット
driver.save_screenshot('shp_screenshot_01_01.png')
# もしMBCニュースの見出し一覧( id=nbox1 の要素)が非表示なら、
# MBCニュースのタブ( id=tab1の要素)を見つけてクリック
if not driver.find_element_by_css_selector("#nbox1").is_displayed():
driver.find_element_by_css_selector("#tab1").click()
# (2) id=tab1 (MBCニュースのタブ)が選択された状態の時点でのスクリーンショット
driver.save_screenshot('shp_screenshot_01_02.png')
# (MBCニュースの見出し (id=nbox1 の要素内にあるliタグで囲まれた部分)の文字を繰り返し参照し、それをprintする
for mbc_news in driver.find_elements_by_css_selector("#nbox1 li"):
print(mbc_news.text)
# 南日本新聞のタブ(id=tab2の要素)を見つけてクリック
# ※このとき、MBCニュースの見出し一覧(id=nbox1 の要素)が非表示から表示された状態に変わる
driver.find_element_by_css_selector("#tab2").click()
# (3) id=tab1 (MBCニュースのタブ)が選択された状態の時点でのスクリーンショット
driver.save_screenshot('shp_screenshot_01_03.png')
# 南日本新聞の見出し(id=nbox2 の要素内にあるliタグで囲まれた部分)の文字を繰り返し参照し、それをprintする
for minami_news in driver.find_elements_by_css_selector("#nbox2 li"):
print(minami_news.text)
driver.quit()
実行結果

(1) 最初に訪れた時点でのスクリーンショット

(2) id=tab1 (MBCニュースのタブ)が選択された状態の時点でのスクリーンショット

(3) id=tab2 (南日本新聞のタブ)が選択された状態の時点でのスクリーンショット

ここでひとつ注意しなければならないのが、Seleniumでは、表示されている状態の文字やパーツしか認識することができません。
シナプスのトップページは、アクセスしたとき、MBCニュースか、もしくは南日本新聞のどちらか片方の見出しがランダムで表示される仕様となっています。
そのため、今回は「MBCニュースの見出し」→「南日本新聞の見出し」の順番に読み取りたいので、アクセス時に「MBCニュース」の見出しが非表示の場合は、MBCのニュースのタブをクリックして表示させる処理を加える必要があります。
(2)シナプスのサイト内検索を実行する
トップページの検索窓で「ソルテ」でGoogleのサイト内検索を実行し、表示された検索結果の中から、リンク先のページタイトルに「電脳」という文字列が入ったページにジャンプします。

以下のように行います。
from selenium import webdriver
import chromedriver_binary
from time import sleep
# ドライバーの準備
options = webdriver.ChromeOptions()
options.add_argument('--headless')
options.add_argument('--no-sandbox')
driver = webdriver.Chrome(options=options)
# 対象のURLを指定
driver.get("https://www.synapse.jp/")
# ウィンドウサイズを指定
driver.set_window_size(1200, 720)
# 「サイト内」のラジオボタン(id=sRadio1 の要素)を見つけてクリック
driver.find_element_by_css_selector("#sRadio1").click()
# 検索窓の入力ボックス(id=sTextの要素)を見つけて選択し、文字列"ソルテ"を送信
texts = driver.find_element_by_id("sText")
texts.send_keys("ソルテ")
# (1)「ソルテ」と入力したところのスクリーンショット
driver.save_screenshot('shp_screenshot_01.png')
# 「検索」ボタン(id=submit-buttonの要素)を見つけてクリック
driver.find_element_by_css_selector("#submit-button").click()
# (2)検索結果のスクリーンショット
driver.save_screenshot('shp_screenshot_02.png')
# 文字列に"電脳"が含まれるリンクテキストを見つけてクリック
driver.find_element_by_partial_link_text('電脳').click()
# Webページのデータをダウンロードしないとスクリーンショットが取れないので5秒待機
sleep(5)
# (3)電脳随想のスクリーンショット
driver.save_screenshot('shp_screenshot_03.png')
driver.quit()
実行結果
(1)「ソルテ」と入力したところのスクリーンショット

(2)検索結果のスクリーンショット

(3)電脳随想のスクリーンショット

Selenium では Google Chrome 以外にも Firefox や Opera など様々なブラウザをCUIで操作することができます。
先程も申し上げました通り、スクレイピングを禁止されているサイトもありますので、ルールの範囲内で試してみてください。