PyInstallerとSleniumのfind_element_by_css_selector超便利


こんばんは、@0yanです。
課メンバーに業務自動化要望をヒアリングしたら、「Webアプリの手作業を自動化して欲しい」という要望があった為、Seleniumで自動化ツールを作成、PyInstallerで実行ファイルにして配布しました。
その際、学びがあったのでこちらで紹介したいと思います。

想定している読者

  • Python+Seleniumで業務自動化しているノンプログラマーや初心者の方
  • コード読めない方から「Webアプリの自動化ツールを作って欲しい」と要望受けている方

コンテンツ

  • PyInstaller超便利
  • Seleniumのfind_element_by_css_selector超便利
  • おまけ:Seleniumで躓きがちなこと

環境

  • Windows10
  • Python 3.7.3(Anaconda3)

PyInstaller超便利

自動化ツール依頼元のメンバーがプログラミング未経験者のため、「環境構築だけで一苦労だろうな・・・どうにか良い方法ないだろうか」と探しておりました。
ありました。
実行ファイル形式で配布するという方法が。

使い方の前に注意事項

普段、Seleniumを使った自動化をする際は、chromedriver-binaryを使った方がラクなので、そうしている方が多いと思います。
が!Seleniumを使ったコードを実行ファイル形式にして配布しても、Chrome Driverが無ければ動きません。

  • Chrome Driverは実行ファイル形式を使うこと前提でコーディングする
  • 実行ファイルとセットでChrome DriverのダウンロードURLも共有、適切なドライバーをダウンロードするよう伝える
  • Chrome Driverの実行ファイルは指定のパスに格納することを伝達する
  • 配布先のPCのデスクトップパス等は、os.environ.get()を使って取得するようにする
  • ログインIDやパスワードの入力を求める際は、input関数を使って最初に求めるようにする

といった配慮が必要です。

PyInstallerの使い方

  1. pip install pyinstallerコマンドでPyInstallerをインストール
  2. pyinstaller ファイル名.py --onefileコマンドを打ち、実行ファイルを作成
  3. distディレクトリに実行ファイルができるので配布する

以上、3stepです。
めっちゃ簡単!

Seleniumのfind_element_by_css_selector超便利

今まで、Seleniumで要素を探す際、
- find_element_by_id
- find_element_by_name
- find_element_by_class_name
- find_element_by_tag_name
- find_element_by_link_text
- find_element_by_partial_link_text
でダメだったら「詰んだ・・・最後の手段だ!」とfind_element_by_xpathメソッドを使っておりましたが、find_element_by_css_selectorメソッドを使えば解決できるということを知りました。
※ここから先、find_element_by_で省略させて頂きます。

使い方①:クラス名の中に空白があっても大丈夫!

HTMLタグ内のクラス名が「class=test hogehoge」となっている場合、~class_nameメソッドでは対応できませんが、~css_selector(.test.hogehoge)とすることで要素取得できます。

使い方②:クラス名が重複してても大丈夫!

例えば、hogehogeというクラス名のHTMLタグが複数あった場合、find_elements_by_class_nameメソッドでそれらをすべて取得、for文で一つずつ目的の要素か否か調べることもできますが、~css_selectorメソッドの引数をタグ名.クラス名タグ名#ID名.クラス名とすることでユニークになれば、for文まわさなくてもいけます。

【具体例1:下記タグが同じページに存在する場合】
1) <select class=hogehoge>
2) <input class=hogehoge>
3) <input id=123 class=hogehoge>
4) <input class=hogehoge name=789>

≪要素取得方法≫
1) find_element_by_css_selector('select.hogehoge')
2) find_element_by_css_selector('input.hogehoge')
3) find_element_by_css_selector('input#123.hogehoge')
4) find_element_by_css_selector('input.hogehoge[name="789"])


【具体例2:divの属性が異なるが、その直下のタグのクラス名や属性がまったく同じ場合】
1) <div class="pb-edit" data-id="1628">の子の<select>タグ
2) <div class="pb-edit" data-id="1629">の子の<select>タグ

≪要素取得方法≫
1) driver.find_element_by_css_selector('div[data-id="1628"] > select)
2) driver.find_element_by_css_selector('div[data-id="1629"] > select)


【具体例3:定期的にクラス名が変わって困る場合】
≪タグ≫
<button placeholder="メンバーを検索" value="" class="Button__DefaultButton-ouh7gw-1 Button__PrimaryButton-ouh7gw-2 SearchBox__SearchButton-sc-1riae5a-1 bHQZyE Button__PrimaryMediumButton-ouh7gw-4 cFhiOs">

≪要素取得方法≫
下記の通り、~css_selector('タグ名[属性名="値"]')でいける。
find_element_by_css_selector('button[placeholder="メンバーを検索"]')

多分、普段CSSを触っている方からしたら「こんな簡単なことも知らんのかい!」と言われるような内容かもしれません。
が、私のようにノンプログラマーでCSSと縁がない人間でも便利に使えるのがPythonの良さだと思いますし、そういう方もいると思いますのでここで共有させて頂きました。

おまけ:Seleniumで躓きがちなこと

ファイルアップロードとスクロールで躓きがちだと思います。
知っている方もいるかと思いますが、こちらで紹介させて頂きます。

ファイルアップロード

Send_keysでできます。

スクロール

画面に表示されていない要素は取得できないため、スクロールしたいこともあると思います。
下記のとおり、ActionChainsクラスを使うことでスクロールできます。

element = driver.find_element_by_id('hogehoge')
action = ActionChains(driver)
action.move_to_element(element)
action.perform()

さいごに

長文にも関わらず、ご覧頂き誠にありがとうございました!
もし、間違い等がございましたらご指摘頂けますと幸いです。
宜しくお願い致しますm(_ _)m

参考サイト

PythonスクリプトをWindows環境で動くexeファイルにしよう!
コマンドプロンプト/Windowsの主要な環境変数一覧と意味
【初心者向け】CSSセレクタとは?セレクタの種類や指定方法を解説!(基礎編)
セレクタの種類
Python3 selenium ローカルファイル選択