Selenium を使って作ったプログラムを以下の記事ではヘッドレス (ディスプレイなし) のラズパイ上の Firefox に移行して実行しました.
しかし,ローカルのパソコンで動かしていた時は動いたのにラズパイに移行すると動かないという事態が生じたので,ディスプレイなしでデバッグする方法を残しておきます.
1. 大まかな流れ
まず,バグの原因を調べるためにログを出力させるのが先決です.
ログを見れば大体何が起こっているかは把握できると思いますが,おそらくローカルのパソコンでは動くのにラズパイに移行すると動かないということは,同じページを開いているはずなのにページの構造が違っているということになると思います.
ページの構造が違っているなら見ればいいのですが,ここで問題が起こります.
ヘッドレスのラズパイ上ではディスプレイがないので開いているページの構造を見ることができないのです!!(当然ですね…)
そこで,ラズパイで開いている画面を何とかして wget
とかを使って取得して解析しようというのが今回の流れになります.
2. ログを出力させる
筆者の書いた以下の記事を参考に作っていた人は try
文を使っているためログが出力されない状態になっていると思います.
ログを出力させるためには try
と except Exception
以下をコメントアウトするか,except
のところを
except Exception as e:
print(e.args)
のようにして,キャッチした例外を出力すればとりあえず OK です.
筆者の場合は以下のようなエラーが出ていました.
Unable to locate element: /html/body/div[1]/div[3]/form/div[1]/div[1]/div[1]/div/div[2]/input
つまりこれは読み込んだウェブサイトで,/html/body/...
という場所を探したけど見つからんかったよということですね.
ローカルで実験していた時はあったはずなのに…となってしまいました.
筆者はここでどうせ近くに同じようなものがあるだろうと思い,エスパーしてローカルと同じ場所を探そうとしましたが見つからなかったので断念しました…
3. ラズパイで開いているページを取得する
このタイトルは “ラズパイで開いているページ” を取得するという意味で,”ラズパイで” 開いているページを取得するではないので,ローカルのパソコンで取得しても構いません.
が,ここでただ以下のように実行しても本当にラズパイで開いているページは取得できない (ことが多い) ので注意してください.
$ wget https://www.google.com/
なぜかというと Web サイトにアクセスする時にはソフトウェアや OS の情報を UserAgent として Web サイト側に送信していて,UserAgentの情報をもとにサイト側がページを返してくるという形になっているので,今ならラズパイの Firefox が送信している UserAgent と同じ情報を Web サイトに送ってあげないといけないということになります.
詳しくは,UserAgentからOS/ブラウザなどの調べかたのまとめ を読んでみてください.
3.1. UserAgent 情報を取得する
そこで,確認くんというサイトを使って UserAgent 情報を取得しましょう.
ラズパイで Firefox を開いた時の UserAgent が知りたいので,Selenium でちょちょっと実装して確認してみましょう.
コード自体はほぼ変えていないのですが,アクセスする URL と取得する要素を変更しました.
from time import sleep
from selenium import webdriver
import os
def main():
# オプションの設定を追加 (方法B の場合は不要)
Options = webdriver.FirefoxOptions()
# ヘッドレス化
Options.headless = True
# 必須
Options.add_argument('--no-sandbox')
Options.add_argument('--disable-gpu')
# エラーの許容
Options.add_argument('--ignore-certificate-errors')
Options.add_argument('--allow-running-insecure-content')
Options.add_argument('--disable-web-security')
# headless では不要そうな機能を除外
Options.add_argument('--disable-desktop-notifications')
Options.add_argument("--disable-extensions")
# UA設定 (なくてもいい)
Options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0')
# 言語 (なくてもいいが言語によって表示されるページが変わる可能性があるので念のため)
Options.add_argument('--lang=ja')
# 画像を読み込まないで軽くする
Options.add_argument('--blink-settings=imagesEnabled=false')
log_path = os.path.join(os.path.dirname(__file__), 'geckodriver.log')
driver = webdriver.Firefox(options=Options, service_log_path=log_path)
driver.implicitly_wait(3)
# 確認くんにアクセスする
page_url = 'https://www.ugtop.com/spill.shtml'
driver.get(page_url)
sleep(1)
# テーブル情報を取得
elem = driver.find_element_by_xpath('/html/body/div[2]/table[2]')
print(elem.text)
driver.close()
if __name__ == "__main__":
main()
ファイルが作れたらこれはラズパイで実行してラズパイで Firefox を使ってアクセスした時の UserAgent 情報を取得してください.
とりあえず,デーブル情報は全て取得しましたが,必要なのは6行目ぐらいの 現在のブラウザー
のところだけです.
今回は Mozilla/5.0 (X11; Linux armv7l; rv:78.0) Gecko/20100101 Firefox/78.0
のようになっていました.
これが UserAgent 情報ですね.
ちなみに,手元の Mac では Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.212 Safari/537.36
となっていたので,当然ですが全く違いますね.
3.2. ページを取得する
UserAgent 情報さえ取得してしまえば後は楽チンです.
ローカルでもラズパイでもいいので,以下のように UserAgent を指定して,wget
コマンドを実行してください.
詳しくは,wgetでこういう時はこうする!! を参考にしてください.
$ wget --user-agent="Mozilla/5.0 (X11; Linux armv7l; rv:78.0) Gecko/20100101 Firefox/78.0" https://www.google.com/
これで無事 “ラズパイで開いているページ” を取得できたと思います.
4. デバッグする
ダウンロードしたファイル (index.html
) をローカルのパソコンで開いて,アクセスしたかった要素をブラウザの検証機能を使って探して,先程 Unable to locate element:
と言われていたところを置き換えれば OK です.
詳しくは,先程もリンクを貼りましたが,Python の Selenium を使って Google Chrome で自動フォーム入力 / スクレイピング でも参考にしてください.
5. まとめ
これで無事ヘッドレスでもデバッグが成功して,アクセスできるようになったと思います.
UserAgent のことなど知らなかったので新しいことが学べてよかったです.