このページでは、Python での Selenium の使い方について解説していきます。特に、このページでは「ウェブブラウザの操作」という観点で、Selenium の使い方の説明を行なっていきます。
Selenium がどういったフレームワークであるのか?については下記ページで解説していますので、Selenium 自体について知りたい方や、Selenium のことをご存知ない方は、まずは下記ページを読んでみていただければと思います。
【Python】Seleniumとは?Contents
Selenium を利用するための前準備
早速 Selenium の使い方について解説していきたいところですが、Selenium を利用する際には前準備が必要となりますので、その準備について解説しておきます。
Selenium 利用時のソフトウェアの全体構成
まず、Selenium を利用時のソフトウェアの全体構成について説明してておきます。これを理解しておけば、Selenium を利用する際に必要となるソフトウェアを自然と洗い出すことができます。その後、必要なソフトウェアのインストール方法の説明していきます。結論を先に言ってしまえば、Selenium を利用する際に必要な準備とは、基本的には Selenium 自体のインストールのみになるかと思います。
ソフトウェアの全体構成
Selenium 利用時のソフトウェアの全体構成は下図のようになります。
まず、今回は Python での Selenium の使い方を解説するページですので、Python から Selenium を利用することになります。なので、当然 Python と Selenium が必要となります。
また、ここでいう Python は Python インタプリタを表しており、Python が Python スクリプトを実行する事になります。そして、この Python スクリプトから Selenium を import
し、Selenium から提供されるクラスやメソッドを利用してウェブブラウザの操作を行うことになります。この Python スクリプトはプログラマー自身が作成する必要があり、Selenium を利用した Python スクリプトの作り方は Selenium の使い方 の章で解説していきます。
さらに、Selenium で実現するのはウェブブラウザの操作となりますので、操作対象となるウェブブラウザも必要です。また、実はウェブブラウザの制御は Selenium が直接行うのではなく、Selenium からの通信による指示を受け、ウェブブラウザのドライバが行う事になります。
したがって、このウェブブラウザのドライバもインストールしておく必要があります。このドライバはウェブブラウザ毎に用意されているため、操作対象のウェブブラウザに合わせてドライバをインストールしておく必要があります。例えば、操作対象のウェブブラウザが Chrome である場合、Chrome ドライバを事前にインストールしておく必要があります。また、この用意するドライバはウェブブラウザのバージョンに合ったものを用意しておく必要があります。
したがって、Selenium を利用する際には、ここまでに紹介してきた Python・Selenium・ウェブブラウザ・そのウェブブラウザのドライバを事前にインストールしておく必要があります。そして、ウェブブラウザの操作が適切に行われるよう Python スクリプトを実装する必要があります。
WebDriver
準備するソフトウェアとしては以上となるのですが、ついでにここで WebDriver
について紹介しておきたいと思います。
この WebDriver
は Selenium から提供されるクラスであり、この WebDriver
のインスタンスがウェブブラウザのドライバと通信を行うことになります。したがって、ウェブブラウザの操作を行うためには、事前に WebDriver
のインスタンスを生成しておく必要があります。そして、この WebDriver
のインスタンスからメソッドを実行してウェブブラウザの操作を実現していくことになります。
また、WebDriver
には各種ウェブブラウザに対応するサブクラスが存在し、実際には WebDriver
のサブクラスのインスタンスがウェブブラウザのドライバと通信を行うことになります。例えば Chrome に対応する WebDriver
のサブクラスとして Chrome
クラスが用意されており、Chrome
クラスのインスタンスが、Python スクリプトからの指示に応じてブラウザのドライバと通信を行うことになります。
このように、WebDriver
とブラウザのドライバとが通信を行うことで、Python スクリプトで記述された処理に応じてウェブブラウザの操作が実現されることになります。
ちょっとややこしいかもしれませんが、ここで重要なのは、Selenium からウェブブラウザの操作を行うためには操作対象のウェブブラウザに応じた WebDriver
のサブクラスのインスタンスを生成する必要があるという点になります。
後述でも解説しますが、これさえ行えばウェブブラウザのドライバも自動的にインストール・起動されることになりますし、Python スクリプトからは WebDriver
のサブクラスのインスタンスへのメソッドの実行により、WebDriver
が必要に応じてウェブブラウザのドライバと通信してくれます。
そのため、ウェブブラウザのドライバの存在は実装時にはほとんど意識する必要はないです。WebDriver
がウェブブラウザの操作・制御を行なってくれていると考えて実装して良いです。
ただ、Selenium を利用してウェブブラウザの操作を行なっても上手く動作しないような場合、もしかしたら原因はウェブブラウザのドライバにある可能性もあります。問題の原因を探る際にはウェブブラウザのドライバも意識する必要があるため、ウェブブラウザのドライバの存在については頭に入れておくと良いと思います。
スポンサーリンク
必要なモジュールのインストール
続いて、Selenium を利用する際に必要となるモジュール等のインストール手順を説明していきます。
Python のインストール
ただし、このページは Python 利用者の方に読んでいただくことを前提としており、既に Python をインストール済みの方が多いと思いますので、Python のインストール方法については説明を省略させていただきたいと思います。
基本的には、下記のサイトから自身の環境(OS)に対応する Python のインストーラーをダウンロードし、それを実行してインストールすれば良いだけになると思います。
https://www.python.org/downloads/
仮想環境を導入し、その環境に Python をインストールしたい場合は「Python 仮想環境」等でググれば情報が出てくると思います。
ウェブブラウザのインストール
続いて、Selenium から操作を行いたいウェブブラウザのインストールを行なっておいてください。このページでは、基本的に後述の解説はウェブブラウザとして Chrome を利用することを前提として説明していきます。そのため、Chrome をインストールしておいていただくと今後の解説が理解しやすくなると思います。
インストール手順は公式の Google のページで解説されていますので、そのリンクだけ紹介しておきます。
https://support.google.com/chrome/answer/95346?hl=ja&co=GENIE.Platform%3DDesktop
Selenium のインストール
続いて、本題となる Selenium をインストールします。
Python をインストールしておけば、Selenium は pip
でインストールすることが可能です。pip
を利用したインストールコマンドの例は下記のようになります。仮想環境を利用している場合は異なる可能性があるので注意してください。
% python -m pip install selenium
コマンド実行後はインストールに成功したかどうかを確認しておきましょう!先程と同様に pip
からインストールに成功しているかどうかを確認可能です。
% python -m pip list
実行結果に、下記のような selenium
の行が存在すればインストールに成功したと判断することができます。右側に表示されているのがバージョンで、インストールタイミングによっては下記よりも新しいバージョンである可能性があります。
selenium 4.9.1
ウェブブラウザのドライバのインストール
準備の最後にウェブブラウザのドライバのインストールを行なっていきましょう。
今回はウェブブラウザとして Chrome を利用することを想定しているため、Chrome ドライバをインストールする必要があります。
…と言いたいところですが、実はウェブブラウザのドライバのインストール手順は不要です。詳細は下記ページで解説していますが、バージョン 4.6 以降の Selenium を利用する場合、Python スクリプトから Selenium を利用する際に、自動的にインストール済みのウェブブラウザに対応したドライバがインストールされるようになっています。
【Selenium】Selenium Managerの紹介【ドライバのインストール手順は不要!】したがって、バージョン 4.6 以降の Selenium を利用する場合、ウェブブラウザのドライバのインストール手順は不要となります。私が記事を書いているタイミングでの Selenium の最新バージョンは 4.9.1 ですので、この記事を読んでくださっているタイミングでインストールを行なったのであればウェブブラウザのドライバのインストールは自動的に行われることになります。
古いバージョンの Selenium を利用している場合は、Selenium のバージョンアップをしておくことをオススメします。
ということで、おそらく、このページを読んでくださっている方は既に Python とウェブブラウザはインストール済みではないかと思いますので、必要となる準備は Selenium のインストール or バージョンアップのみとなります。
実は、Selenium を利用する上でのネックはウェブブラウザのドライバのインストール手順だったのですが、これが不要となったため、Selenium はかなり使いやすくなっています。
Selenium の使い方
Selenium を使う準備が整ったので、次は Selenium の実際の使い方、すなわち Selenium を利用する際の Python スクリプトの実装手順について解説していきます!
Selenium を利用する際の処理の流れ
最初に、Selenium を利用する際の処理の流れを簡単に説明しておきます。
Selenium を利用するための前準備 でも説明したように、Python スクリプトからは WebDriver
のサブクラスのインスタンスを生成し、そのインスタンスからドライバを介してウェブブラウザの操作を行うことになります。そのため、Selenium でウェブブラウザを操作するためには、その操作対象となるウェブブラウザに対応する WebDriver
のサブクラスのインスタンスを生成する必要があります。
WebDriver
および WebDriver
のサブクラスは webdriver
モジュールで定義されていますので、webdriver
の import
が必須となります。その他の import
が必要なモジュールに関しては必要になったタイミングで随時紹介していきます。
また、今回は操作対象のウェブブラウザを Chrome として解説していきたいと思います。この場合、WebDriver
のサブクラスとしては Chrome
クラスを利用することになり、Chrome
クラスのインスタンスを生成することになります。
WebDriver
のサブクラスのインスタンス生成時には、ウェブブラウザのドライバとウェブブラウザ自体の起動も行われます。従って、Chrome
クラスのインスタンスを生成すれば自動的に Chrome ドライバと Chrome が起動することになります。
そのため、あとは基本的に自身が行いたいウェブブラウザの操作に対応するメソッドを実行してやれば良いだけになります。
ただ、ウェブブラウザの操作を行う目的はウェブブラウザ上に表示されたページに対して操作を行うことであることが多く、基本的には WebDriver
のサブクラスのインスタンス生成後にページの表示を行う処理が必要となります。
そして、ページの表示を行なった後は、ページ上の特定の要素に対して操作を行っていくことになります。例えば、ページ上の特定のボタン要素に対してクリックを行ったり、ページ上の特定の入力フィールド要素に対して文字列を入力したり、といった操作を行なっていくことになります。
ただ、こう言った特定の要素に対する操作を実施する際には、事前にその要素を取得しておく必要があります。したがって、ページ上の特定の要素に対する操作を実現する際には、まず操作対象の要素を探索して取得し、その取得した要素に対して操作を行うという2段階の手順が必要となります。
そして、この要素の取得および要素への操作を繰り返し実行することで、ウェブブラウザに対する様々な操作を自動的に行うことができるようになります。
ウェブブラウザに対する操作が全て完了すれば、最後にウェブブラウザを終了します。
まとめると、Selenium を利用してウェブブラウザの操作を行う際には、下記のような手順を実施する必要があります。
WebDriver
のサブクラスのインスタンスを生成する- ウェブブラウザのドライバとウェブブラウザが起動する
- ページを表示する
- ページ内の要素を取得する
- 取得した要素に対して操作を行う
(3. と 4. は必要な分だけ繰り返す) - ウェブブラウザを終了させる
これはあくまでも基本的な流れであって、この流れに必ずしも従う必要はありません。例えばウェブスクレイピングを行うのであれば、2. の「ページを表示する」を実行した後、そのページの HTML を取得して Beautiful Soup などによって HTML を解析するような流れになると思います。
このページでは、上記の基本的な流れに従ってウェブブラウザ(およびウェブブラウザに表示されるページの各種要素)に対する操作を行う手順を示していきますが、自身のやりたいことに応じて処理の流れは臨機応変に変更していただければと思います。
スポンサーリンク
WebDriver
のサブクラスのインスタンスを生成する
続いて、先ほど示した各種手順についての詳細を解説していきます。
まずは WebDriver
のサブクラスのインスタンスの生成について解説していきます。
Chrome 操作時のインスタンスの生成
前述でも少し触れましたが、WebDriver
のサブクラスは webdriver
というモジュールから定義されることになります。そのため、事前に webdriver
を import
しておく必要があります。そして、この import
後に、WebDriver
のサブクラスのコンストラクタを実行してインスタンスの生成を行います。
例えば Chrome の操作を行う際には下記のように webdriver.Chrome()
、すなわち Chrome
クラスのコンストラクタを実行してインスタンスの生成を行います。
from selenium import webdriver
driver = webdriver.Chrome()
以降で説明するウェブブラウザの操作は、基本的には WebDriver
のサブクラスのインスタンス or 取得した要素のインスタンスからメソッドを実行することで実現していくことになります。
ここからは、WebDriver
のサブクラスのインスタンスのことを単に driver
と呼ばせていただきます。
ドライバとブラウザの起動
前述でも触れましたが、WebDriver
のサブクラスのコンストラクタを実行した際には、そのサブクラスに対応するウェブブラウザのドライバとウェブブラウザ自体が起動することになります。例えば webdriver.Chrome()
を実行した際には、Chrome ドライバと Chrome 自体の起動も行われることになります。
また、ウェブブラウザに対応するドライバが存在しない場合、Selenium Manager と呼ばれるツールが実行され、そのウェブブラウザに対応するドライバが自動的にインストールされ、インストール後に、そのドライバが起動されることになります。
そのため、WebDriver
のサブクラスのコンストラクタを実行さえすれば、Selenium からウェブブラウザの操作を行うにあたって必要になるソフトウェアが全て起動することになります。ですので、WebDriver
のサブクラスのコンストラクタを実行して driver
を生成すれば、後は driver
からメソッドを実行してWebブラウザの操作を行なっていけば良いことになります。
古いバージョンの Selenium では、WebDriver
のサブクラスに executable_path
引数を指定してプログラマーが明示的にドライバのパスを指定する必要がありました
ですが、最近の Selenium では自動的にドライバのパスが設定されるようになっているため(さらには、存在しない場合は自動的にドライバのインストールも行われる)、executable_path
引数の指定は不要となっています
他のウェブブラウザの操作
先ほどは Chrome の操作を行う例で解説を行なってきましたが、Selenium からは Chrome 以外のウェブブラウザの操作を行うことも可能です。他のウェブブラウザを操作したい場合は下記部分を変更する必要があります。
driver = webdriver.Chrome()
前述でも説明したように、Chrome
は WebDriver
のサブクラスの1つで、同様のサブクラスがウェブブラウザごとに用意されています。なので、Chrome 以外のウェブブラウザを操作したいのであれば、Chrome
ではなく他のクラスのインスタンスを生成する必要があります。例えば、Safari を操作したいのであれば Safari
、Edge を操作したいのであれば Edge
クラスのインスタンスを生成することになります。
例えば下記は、Edge を操作するために Edge
のインスタンスを生成する例になります。もし Edge ドライバがインストールされていなければ、Edge()
実行時にドライバのインストールも自動的に行われます。この点も Chrome の時と同様になります。
# 2. WebDriver のインスタンス生成
driver = webdriver.Edge()
私も詳細な確認をしたわけではないのですが、手作業時に行うブラウザでの操作は各ブラウザで基本的に同じであるため、使用する WebDriver
のサブクラスを変更したとしても、それ以降に行う処理はウェブブラウザの種類に依存しないはずです。例えば Selenium でのウェブアプリの操作例 で Selenium を利用したウェブブラウザ操作の例を紹介しますが、そこで示すソースコードは上記のように使用する WebDriver
を Edge
に変更しても上手く動作することを確認しています。
また、ウェブブラウザによっては、Selenium から利用する際にそのウェブブラウザ独自のお作法が必要になることもあるので注意してください。例えば Safari の場合は、ウェブブラウザから操作を行うために事前に「開発」メニューから「リモートオートメーションを許可」にチェックを入れておく必要があります。
また、Safari のメニューに「開発」メニューが表示されていない場合は、事前に Safari の環境設定の「詳細」タブで メニューバーに"開発"メニューを表示
にチェックを入れておく必要があります。
こんな感じで、他のウェブブラウザも操作可能ではあるものの、ウェブブラウザによっては Selenium から操作するために独自の作法が必要になることもあるので注意してください。Chrome の操作に関する情報はネット上にも多く存在するので、こだわりがなければ Chrome でのウェブブラウザの操作をまず試してみるのが良いと思います。
オプションの指定
また、WebDriver
のインスタンスを生成する際にはオプションを指定することが可能です。
オプションを指定する際には、まず Options
クラスのインスタンスを生成し、そのインスタンスから add_argument
メソッドを実行させてオプション指定の追加を行い、その後 WebDriver
のコンストラクタ(WebDriver
のサブクラスのコンストラクタ)の options
引数にインスタンスを指定することになります。
実際のソースコードとしては下記のようなものになります。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
options = Options()
options.add_argument('--headless')
driver = webdriver.Chrome(options=options)
ポイントは、Options
クラスはウェブブラウザ毎に用意されている点になります。そのため、そのウェブブラウザに対応する Options
クラスのインスタンスを生成する必要があります。Chrome の場合は、上記のように selenium.webdriver.chrome.options
で定義されている Options
クラスを利用する必要があります。
また、上記ではオプションで --headless
を指定しており、これによりウェブブラウザが起動しても画面に表示されないようになります。これは結構利用機会の多いオプションになると思いますので是非覚えておいてください。
ページを表示する
driver
を生成した後は、基本的にはページの表示を行うことになります。
ページの表示は、driver
から get
メソッドを実行させることで実現することができます。引数には表示したいページの URL を指定します。
driver.get('開きたいページのURL')
get
メソッドを実行すればウェブブラウザにページ表示の指示が出され、ウェブブラウザから引数で指定した URL のページを表示するためのリクエストがウェブサーバー等に送信されます。そして、そのリクエストの送信に対するレスポンスとして HTML・CSS・JavaScript 等を受け取り、それがページとしてウェブブラウザに描画されて表示されることになります。
これは、手動でウェブブラウザの URL バーに URL を指定する時と同じ動作であり、人ではなく Selenium が URL の指定を行うようになるだけです。
例えば、get
メソッドの引数に https://google.com
を指定すれば、お馴染みの Google のトップページを表示することができます。
そして、ページの表示によって、ページ内にボタンや入力フィールド等の要素が表示されますので、これらの要素に対して操作を行なっていくことになります。
ページ内の要素を取得する
では、続いてページ内の要素の操作方法について解説していきます。
要素を操作するとは?
ページ内の要素の操作に関しては、下記の2つの操作を組み合わせることで実現することになります。要素とは、ページ内を構成する部品のようなものであり、例としてボタン・入力フィールド・リンク・段落・見出しなどが挙げられます。
- ページ内の要素を探索する
- 見つけた要素に対して操作を行う
皆さんもマウス等を利用してウェブブラウザからページ内のボタンをクリックしたことがあると思います。その際には、大きく分けて下記の2つのようなことを行なっているのではないかと思います。
- 目でクリックしたいボタンの位置を探索する
- 見つけた位置に対してクリックを行う
基本的にはページ内には複数の要素が存在します。そのため、まず、その中からクリックしたい要素を見つけて特定することが必要となります。そして見つけた後に、クリックなどの操作を行うことになります。
このように、ページ内の要素に対して操作を行う際には、人間が手作業で操作を行うにしても、操作対象の要素を見つけ、その見つけた要素に対して操作を行うという2つの動作が必要となります。そして、これは Selenium で操作を行う際にも同様のことが言えます。つまり、Selenium で要素に対して操作を行う際にも、まずその要素を探索して見つけ出し、その見つけた要素に対して操作を行う必要があります。
そして、ここではまず、前者の要素の探索方法について解説していきます。
要素の探索方法
では、Selenium で操作対象の要素はどうやって探索すれば良いのでしょうか?
人間が手作業で操作を行う際には基本的には目で探索することが多いと思いますが、Selenium の場合は HTML の構造を利用して要素の探索を行います。
ウェブブラウザで表示されるページは HTML から構成されています。そして、ページ内の各要素は HTML 内にタグとして記述されています。Selenium で要素の操作を行う場合、まずは、この HTML 内のタグを頼りに探索することになります。
例えば、タグには id
属性が指定されていることがあります。この id
属性は、タグに付加されたユニークな識別子であり、この id
属性を利用してタグを探索することができます。
find_element
メソッド
さらに、この要素の探索を行う際には、WebDriver
クラスの提供する find_element
メソッドを利用します。WebDriver
が提供するメソッドですので、Chrome
等の WebDriver
のサブクラスのインスタンスからも find_element
は実行可能です。
find_element
は下記の形式で引数を指定して実行することが多いです。find_element
を実行する driver
は WebDriver
のサブクラスのインスタンスである必要があります。
elem = driver.find_element(by, value)
引数の by
と value
は要素の探索条件を指定する引数となります。つまり、find_element
は by
と value
とで指定する探索条件に一致する要素を見つけ出し、その要素を返却値として返却するメソッドとなります。返却される要素の数は1つのみとなります。
より具体的には、by
には探索対象とする項目名を、value
に探索対象とする項目の値を指定します。例えば、下記のように find_element
の引数を指定した場合、探索対象とする項目名が ID
で、さらに、その ID
が send_button
である要素の探索が行われることになります。
from selenium.webdriver.common.by import By
button = driver.find_element(by=By.ID, value='send_button')
これはすなわち、タグに設定されている id
属性が send_button
である要素を探索する命令となります。そして、この探索条件に一致する要素が見つかった場合に返却値として目当ての要素を取得することができます。見つからなかった場合は例外が発生します。
例えば、下の図のような4つのボタンが存在するページにおいて、Send
ボタンをクリックしたいとしましょう。このページには複数のボタンがあるので、この中からまず Send
ボタンを探索して取得する必要があります。
さらに、このページが下記のような HTML によって描画されているとします。この HTML の中で input
タグがボタン要素に対応しており、4つ input
タグあるのでページには4つのボタンが表示されることになります。Selenium で Send
ボタンのクリックを実現したい場合、まずは下記の HTML の中から Send
ボタンを探索して取得する必要があります。
<html>
<head>
<title>Buttons</title>
</head>
<body>
<input id="ok_button" name="ok" value="OK" type="submit">
<input id="cancel_button" name="cancel" value="Cancel" type="submit">
<input id="send_button" name="send" value="Send" type="submit">
<input id="skip_button" name="skip" value="Skip" type="submit">
</body>
</html>
そして、その Send
ボタンの取得を実現するのが、前述でも示した下記の処理となります。Selenium を利用してページを表示した後に下記のように find_element
を実行すれば、id
属性が send_button
である要素の探索が行われます。その結果、上記の HTML には id
属性が send_button
である input
要素が存在するため、この input
要素を取得することができることになります。 そして、この input
要素はページの描画結果において左から3つ目の要素、すなわち Send
ボタンとなります。
from selenium.webdriver.common.by import By
button = driver.find_element(by=By.ID, value='send_button')
上記の find_element
メソッドの実行によって、Send
ボタン要素が button
として取得することができることになるため、後はこの button
に対して操作、例えばクリック操作を行えば、「Send
ボタンのクリック」という操作を実現することができることになります。
このように、find_element
を利用することで要素をページ内から探索して取得し、その要素に対して操作を実行するのが、ページ内の要素への操作を行う一連の流れとなります。
また、ここでは id
属性での探索例を示しましたが、by
引数に指定する値を変更すれば、他の項目で探索を行うこともできます。by
引数に指定可能な値に関しては、後述の by 引数に指定可能な値 で紹介します。
find_elements
メソッド
find_element
が1つの要素のみを返却するのに対し、find_elements
は見つかった全ての要素を返却するメソッドとなります。つまり、find_elements
メソッド利用すれば、複数の要素を一度に取得することができます。
引数に関しては find_element
と同様で、find_elements
メソッドの引数には by
と value
の2つで探索条件を指定して実行することになります。ただし、find_element
の返却値が1つの要素のみであるのに対し、find_elements
メソッドの返却値は見つかった全ての要素が格納されたリストとなります。探索条件に一致する要素が見つからなかった場合は空のリストが返却されることになります。
例えば、先ほど示した下記の HTML によって表示されるページの場合、
<html>
<head>
<title>Buttons</title>
</head>
<body>
<input id="ok_button" name="ok" value="OK" type="submit">
<input id="cancel_button" name="cancel" value="Cancel" type="submit">
<input id="send_button" name="send" value="Send" type="submit">
<input id="skip_button" name="skip" value="Skip" type="submit">
</body>
</html>
下記のように find_elements
を実行すれば、4つのボタン要素を持つリストが返却されることになります。そして、このリストに対して for
文でループを回せば、リストの持つ全ての要素に対して操作を行うようなことも可能となります。
from selenium.webdriver.common.by import By
buttons = driver.find_elements(by=By.TAG_NAME, value='input')
for button in buttons:
button.click()
by
引数に指定可能な値
先ほどの find_element
の使用例では by
引数に By.ID
を、find_elements
の使用例では by
引数に By.TAG_NAME
を指定する例を示しました。
この2つの例からも察していただけるように、by
引数には他にも様々な値を指定することが可能です。具体的な by
に指定可能な値は下記となります。これらは全て、By
クラスから提供されるクラス変数として定義されていますので、事前に By
クラスの import
をしておく必要があります。
By.ID
:タグのid
属性で探索By.XPATH
:XPath で探索By.LINK_TEXT
:タグのリンクテキストで探索(全一致)By.PARTIAL_LINK_TEXT
:タグのリンクテキストで探索(部分一致)By.NAME
:タグのname
属性で探索By.TAG_NAME
:タグ名で探索By.CLASS_NAME
:タグのclass
属性で探索By.CSS_SELECTOR
:CSS セレクタで探索
一番分かりやすいのが By.ID
や By.NAME
あたりになると思います。これらは HTML のタグの属性として指定されている id
属性 と name
属性を探索対象とするための指定となります。なので、特定の要素に対して操作を行いたい場合、まずは HTML を調べ、特定の要素に対応するタグの属性を調べてやれば value
に指定すべき値を特定することができます。
ただし、id
属性 と name
属性は必須の属性では無いため、こららの属性が指定されていないタグも存在します。こういった場合は、どうやって特定の要素を探索すれば良いのでしょうか?
個人的にオススメなのは By.XPATH
での探索になります。XPath って何?って思われる方も多いと思いますが、簡単に言ってしまえば、ページ内の要素の位置を特定するためのパスになります。これを聞いてもピンと来ない方も多いと思います。正直 XPath を完全に理解するのは難しいです…。
ですが、Selenium でページ内の要素を操作するだけであれば、XPath について深く理解しておく必要はないです。Selenium でページ内の要素に対して操作を行うために理解しておくべきことは、この XPath が要素を特定するための情報あること、かつ、この XPath は Chrome 等の検証機能を利用すれば簡単に調べることが可能であることの2つになります。
要は、Chrome さえあれば、ページ内の要素に対応する XPath を簡単に調べることができ、あとは find_element
や find_elements
を実行する際に by
引数に By.XPATH
を、value
引数に調べた XPath を指定してやれば、操作対象とする要素を簡単に取得することができます。
個人的にオススメなのは By.XPATH
になりますが、同様に Chrome で CSS セレクタも簡単に調べることができるため、By.CSS_SELECTOR
を利用するのでも良いと思います。いずれにしても、Chrome を利用することで Selenium での要素の探索が簡単に行うことができるという点がポイントとなります。
検証機能のでの XPath の取得
ということで、Selenium を利用する上では検証機能の利用方法を知っておいた方が良いです。
そのため、ここで簡単に Chrome での検証機能の利用方法について解説しておきます。この検証機能は非常に便利&無料で誰でも利用できる機能ですので、是非この機会に検証機能の使い方を覚えておきましょう!
検証機能を利用するためには、まず Chrome を起動して何らかのページを開きます。
そして、ページの中から操作対象としたい要素にマウスカーソルを合わせ、右クリックを行います。そして、右クリックメニューの中から 検証
を選択します。
すると、おそらくページの右側に検証タブが表示され、先ほど右クリックした要素に対応するタグがハイライトされた状態で表示されているはずです。
次は、そのハイライトされているタグを右クリックし、右クリックメニューから コピー
を選択、さらに、それによって表示されるコピーメニューの中から XPathを コピー
を選択します。
これにより、右クリックした要素の XPath がクリップボードにコピーされたことになります。
あとは、find_element
や find_elements
メソッドの value
引数にペーストしてやれば、探索対象とする要素の XPath の指定は完了となります。この手順の場合、value
には XPath を指定することになるため by
引数に By.XPATH
を指定することを忘れないようにしてください。
具体的に XPath を指定した find_element
メソッドの実行例は下記のようなものになります。value
に指定している値が XPath で、XPath や HTML に詳しくない方にとっては意味不明かもしれないですが、上記の手順で XPath を指定してやれば、右クリックした要素をうまく取得することができるはずです。
elem = driver.find_element(by=By.XPATH, value='//*[@id="login-form"]/div[3]/input')
このように、XPath は Chrome の検証機能を利用することで簡単に取得することができます。そして、この XPath の取得さえしてやれば、find_element
や find_elements
メソッドの実行によって操作対象となる要素の取得を簡単に実現することができます。
もちろん、ここで実現すべきことは操作対象となる要素を取得することですので、別に XPath に拘る必要はないです。ですが、検証機能によって XPath が簡単に取得できることは覚えておくと良いと思います。ただし、XPath は万能というわけではなく、状況によっては XPath を指定すると目的の要素とは異なる要素が取得できてしまうようなケースもあります。この点に関しては、Selenium でのウェブアプリの操作例 で実例を示しながら説明していきたいと思います。
また、取得したい要素のタグも調べやすいので、XPath を調べるときだけでなく id
属性や name
属性そ調べる際にも検証機能は活躍すると思います。
ワイルドカード
また、value
引数にはワイルドカード *
(アスタリスク) が利用可能であることも覚えておくと良いと思います。例えば前述で示した下記においては value
引数にワイルドカード *
が利用されており、この *
部分は任意の文字列として扱われることになります。つまり、*
部分に関してはどんな文字列であっても良いことになります。
elem = driver.find_element(by=By.XPATH, value='//*[@id="login-form"]/div[3]/input')
したがって、ページを表示した後に下記を実行することでページ内の全要素を取得するようなこともできます。下記では by=By.TAG_NAME
と value='*'
を指定しているため、タグ名に関わらず要素の取得が行われるため、結果的に全要素を取得することができることになります。
elems = driver.find_elements(by=By.TAG_NAME, value='*')
今回はウェブブラウザの操作に焦点を当てており、この場合は、どちらかというと多くの要素を取得することよりも操作対象となる特定の要素に限定して取得することが重要となります。そのため、ワイルドカードを利用する機会は少ないかもしれませんが、ワイルドカードが利用可能であることは覚えておくと良いと思います。
スポンサーリンク
取得した要素を操作する
find_element
や find_elements
で要素を取得したあとは、その要素に対して操作を行うことになります。
この操作は、取得した要素のインスタンスからメソッドを実行することで実現することができます。続いて、要素のインスタンスから実行可能なメソッドのいくつかを紹介していきます。
click
一番分かりやすいのが要素に対するクリック操作になると思います。このクリック操作は、click
メソッドの実行により実現することができます。
例えば、フォーム内のボタン要素をクリックすることでデータの送信を行うようなこともできますし、チェックボックス要素に対してクリックを行うことでチェックの ON / OFF を切り替えるようなこともできます。
button = driver.find_element(by=By.XPATH, value='ボタンのXPath')
button.click()
send_key
また、入力フィールド等の要素のインスタンスに send_key
メソッドを実行することで文字列を入力することができます。
send_key
メソッドの引数には入力したい文字列を指定します。
input_field = driver.find_element(by=By.XPATH, value='入力フィールドのXPath')
input_field.send_key('YamadaHanako')
clear
また、逆に入力フィールド等の要素のインスタンスに clear
メソッドを実行することで文字列をクリアすることもできます。
clear
メソッドの引数への引数指定は不要です。
input_field = driver.find_element(by=By.XPATH, value='入力フィールドのXPath')
input_field.clear()
is_selected
また、is_selected
メソッドで要素が選択中であるかどうかを調べることもできます。
例えば、is_selected
メソッドによりチェックボックスのチェックが ON / OFF のどちらであるかを調べるようなことができます。
チェックボックス要素のインスタンスに is_selected
メソッドを実行させれば、チェックが ON の時には True
が、チェックが OFF の時には False
が返却されることになります。したがって、is_selected
メソッドの返却値が False
の場合のみ click
メソッドを実行させるようにすれば、そのチェックボックスのチェックを確実に ON にすることができます。
check_box = driver.find_element(by=By.XPATH, value='チェックボックのXPath')
if not check_box.is_selected():
check_box.click()
find_element
・find_elements
これは要素に対する操作とは少し違うものになりますが、要素のインスタンスからは find_element
や find_elements
を実行することもできます。
HTML では、要素の中に他の要素が存在するような構成のものが存在します。例えば下記では、div
タグの要素の中にボタン要素が存在しています。
<html>
<head>
<title>Buttons</title>
</head>
<body>
<div id="section1">
<input id="ok_button" name="ok" value="OK" type="submit">
<input id="cancel_button" name="cancel" value="Cancel" type="submit">
</div>
<div id="section2">
<input id="send_button" name="send" value="Send" type="submit">
<input id="skip_button" name="skip" value="Skip" type="submit">
</div>
</body>
</html>
上記のような HTML のページにおいて、id
属性が section2
の div
タグの要素の中にあるボタンを全てクリックするような操作は下記のような処理によって実現することができます。
div = driver.find_element(by=By.ID, value='section2')
buttons = div.find_elements(by=By.TAG_NAME, value='input')
for button in buttons:
button.click()
Selenium を使いこなすポイントの1つは要素の取得になります。要素から find_element
等を実行させることで、上記のように段階的に要素を限定しながら最終的な操作対象の要素を探していくことができる点も覚えておくと良いと思います。
データ属性
また、これはメソッドではありませんが、各要素のインスタンスから利用可能なデータ属性の一部、およびそれらの意味合いについてもいくつか紹介しておきます。
location
:要素の位置size
:要素のサイズrect
:要素のサイズと位置tag_name
:要素のタグ名text
:要素の本文screenshot_as_png
:要素のスクリーンショット
よく利用するのは text
になると思います。例えば段落要素は <p>段落の本文</p>
のような形式で記述されます。この 段落の本文
部分を取得したければ、まずはこの p
タグの要素を取得し、その要素の text
データ属性を参照すれば良いことになります。
また、使い所は多くないかもしれないですが、screenshot_as_png
から要素のスクリーンショット画像が取得できる点も面白い点になると思います。
screenshot_as_png
を利用することで、例えば下記のようにページ内の全要素のスクリーンショット画像を保存するようなことも可能になります。要素によってはサイズ(幅と高さ)が 0
のものもあるので、それらの要素を除いてスクリーンショットを保存するようになっています。
要素が大量に存在するページを表示してから下記を実行すると大量のスクリーンショット画像が PC に保存されることになるので注意してください。
elems = driver.find_elements(by=By.TAG_NAME, value='*')
for i, elem in enumerate(elems):
if elem.size['height'] != 0 and elem.size['width'] != 0:
with open('{}_{}.png'.format(elem.tag_name, i), 'wb') as f:
f.write(elem.screenshot_as_png)
また、上記の例を見ていただくことで、要素のデータ属性よりサイズやタグ名を取得することができることも確認していただけると思います。
ウェブブラウザを終了させる
ページ内の要素に対する操作が完了すれば、後はウェブブラウザを終了させて作業完了となります。このウェブブラウザの終了は driver
から quit
メソッドを実行することで実現できます。
quit
メソッドを実行した場合、ウェブブラウザが終了し、ウェブブラウザのドライバも終了することになります。
driver.quit()
ウェブブラウザ自体を操作する
ここまでが、ウェブブラウザの操作を行う際の Selenium での基本的な処理の流れとなります。
基本的に、ここまでは特にウェブブラウザ上に表示されたページの要素を操作することに焦点を当てて解説を行なってきましたが、続いてウェブブラウザ自体に対する操作の実現方法を説明しておきたい思います。
これらも基本的には、WebDriver
に用意されたメソッドを利用して実現していくことになりますので、操作対象のウェブブラウザに対応する WebDriver
のサブクラスのインスタンスを生成した後にメソッドを実行してウェブブラウザ自体の操作を行なっていくことになります。以降に紹介するメソッドの実行例においては、このインスタンスが driver
であることを前提としたものになっています。
スクリーンショットの撮影
最初に紹介するのがスクリーンショットの撮影になります。
このスクリーンショットの撮影は save_screenshot
メソッドの実行によって行うことができます。save_screenshot
メソッドを実行することで、実行したタイミングでウェブブラウザに表示されているページのスクリーンショットが撮影され、引数で指定したパスに PNG 画像ファイルとして保存することができます。
driver.save_screenshot('screenshot.png')
前述の データ属性 で要素単体のスクリーンショットをデータ属性から取得可能であることを説明しましたが、save_screenshot
では要素単体ではなくウェブブラウザに表示されている部分全体のスクリーンショットを撮影することが可能となります。
もしかしたらバージョン等によって異なるかもしれませんが、どうもソースコードを見た感じだと、保存する画像のフォーマットは PNG のみとなっているようでした(引数に拡張子が .jpg
などの .png
以外を指定しても、結局 PNG 画像として保存される)。
また、撮影したスクリーンショットをファイルに保存するのではなく、画像データとして取得したい場合は get_screenshot_as_png
メソッドを利用してやれば良いです。
例えば下記のように処理を行えば、撮影したスクリーンショットを PIL の画像オブジェクトとして扱うことができます。
png_data = driver.get_screenshot_as_png()
img = Image.open(io.BytesIO(png_data))
戻る・進む・更新
また、ウェブブラウザに用意されている「戻る」「進む」「更新」操作を Selenium から行うこともできます。これらはそれぞれ back
・forward
・refresh
メソッドにより実現できます。
driver.back()
driver.forward()
driver.refresh()
タブの新規追加とタブの終了
また、ウェブブラウザのウィンドウにタブを新規追加し、そのタブ上にページを表示するようなこともできます。タブの新規追加は、driver
の switch_to
データ属性から new_window
メソッドを実行することで実現できます(引数には 'tab'
を指定します)。
また、driver
から操作を行なっているタブやウィンドウのみを閉じる際には close
メソッドを実行してやれば良いです(前述で紹介した quit
メソッドの場合は、ウェブブラウザ自体が終了することになります)。
例えば下記を実行すれば、ウェブブラウザのウィンドウにタブが新規追加され、そのタブで Google のトップページが表示されることになります。そして、最後の close
メソッドにより、そのタブが閉じられることになります。
driver.switch_to.new_window('tab')
driver.get('https://google.com')
driver.close()
ここでポイントになるのが、driver.switch_to.new_window
を実行すると、driver
からの操作対象が新規追加したタブに移るという点になります。なので、次の行で get
メソッドを実行することで、新規追加したタブに Google のページが表示されることになります。
この操作対象が移るという点は、タブを閉じた時に注意が必要となります。タブを閉じたとしても driver
からの操作対象は閉じたタブのままになります。
なので、その後 driver
から何かしらの操作を行おうとしても、閉じたタブに対して操作を行うことになってしまって例外が発生することになります。これを防ぐためには、操作対象を元々開いていたタブに戻す等の処理が必要となります。この処理を行うのが driver.switch_to.window
メソッドとなります。
先ほど示したソースコードに対し、「操作対象を元々開いていたタブに戻す処理」を追加したものが下記となります。
original = driver.current_window_handle
driver.switch_to.new_window('tab')
driver.get('https://google.com')
driver.close()
driver.switch_to.window(original)
上記において、操作対象を元々のタブに戻す処理を行なっているのが最後の行となります。この最後の行で実行している driver.switch_to.window
は操作対象を他のタブ・ウィンドウに移すメソッドになります。引数には、操作対象の移動先となるタブやウィンドウのハンドルを指定する必要があります。ハンドルとは識別子みたいなものです。
で、ここで行いたいのは新たな操作対象を「元々操作していたタブ」に戻すことですので、1行目で保存しておいたハンドルを window
メソッドの引数に指定するようにしています。driver.current_window_handle
は、今現在 driver
から操作しているウィンドウ(タブ)のハンドルを管理するデータ属性となります。
したがって、上記のような流れで処理を実行すれば、新たにタブを追加し、そのタブを閉じたとしても、以降の操作を元々操作していたタブに対して実行することができるようになります。
また、ここではタブに焦点を当てて解説を行いましたが、driver.switch_to.new_window('tab')
ではなく driver.switch_to.new_window('windows')
に変更すれば、新規ウィンドウを作成し、そのウィンドウに対して操作を行うことができるようになります。閉じ方や閉じた後の操作対象の変更方法はタブの時と同様になります。
ウィンドウサイズ関連の設定
また、ウェブブラウザのウィンドウサイズやウィンドウの位置を変更するようなことも可能です。
ウィンドウサイズ関連の設定を行うメソッドには下記のようなものが存在します。
maximize_window
:ウィンドウのサイズを最大化するminimize_window
:ウィンドウのサイズを最小化するset_window_size
:ウィンドウのサイズを第1引数で指定した幅・第2引数で指定した高さに設定するset_window_position
:ウィンドウの左上の位置を第1引数で指定した x 座標・第2引数で指定した y 座標に移動する
サイズや座標はピクセル単位で指定する必要があります。また、座標の原点はパソコンの画面の左上端となります。
下記は、これらのメソッドの実行例となります。
driver.maximize_window()
driver.minimize_window()
driver.set_window_size(100, 200)
driver.set_window_position(500, 300)
スクリプトの実行
また、Selenium では表示しているページに対して JavaScript を実行するようなことも可能となっています。この JavaScript の実行は execute_script
メソッドによって行うことができます。
driver.execute_script("JavaScriptの処理")
execute_script
メソッドを利用することで、Selenium のみでは実現できない操作も JavaScript の実行によって実現することも可能となります。
例えば、Selenium にはページのスクロールを行うようなメソッドは用意されていませんが、JavaScript を利用すればページのスクロールを実行することが可能です。例えば下記はページを 100
px 分だけ下方向にスクロールする処理の例となります。
driver.execute_script("window.scrollBy(0, 100);")
このように、execute_script
メソッドによって JavaScript を実行することで実現可能なウェブブラウザへの操作の幅を広げることができます。
スポンサーリンク
Selenium でのウェブアプリの操作例
Selenium の使い方の解説は以上となります。
最後に、ここまでの解説内容の復習の意味も込めて、Selenium でのウェブアプリの操作例を示していきたいと思います。
今回は Django を利用してウェブアプリを動作させ、そのウェブアプリに対する操作を Selenium から行なっていきたいと思います。Django は Python におけるウェブアプリ開発用フレームワークの1つで、Django を利用することで簡単にウェブアプリを開発することができます。Django 自体については下記ページで解説していますので、興味がある人は読んでみていただければと思います。
【Django入門1】Djangoとは?ちょっと Django でウェブアプリを用意するのが面倒かもしれませんが、実際にネット上で公開されているウェブアプリの操作を行なったりするとサーバーに負荷がかかって運営者や利用者に迷惑をかけてしまう可能性があります。ですが、ここから説明する方法で用意するウェブアプリは自身の PC 上で動作することになるため、好きなだけ Selenim を利用した操作や動作確認を行うことができます。
また、今回は Django で開発したウェブアプリというよりは、Django のウェブアプリに予め用意される管理画面に対して Selenium からの操作を実施していきます。この管理画面では、ウェブアプリのユーザーの登録や削除などを実施することが可能で、これらを Selenium を利用して Python スクリプトから実行していく例を示していきます。また、管理画面を利用するためには事前にログインを行う必要もあります。これに関しても Selenium を利用して実現していきます。
ウェブアプリの準備
ということで、ウェブアプリを Django で準備していきたいと思います。といっても、今回は Django でプロジェクトを作成すると自動的に用意される管理画面を利用するため、コマンドをいくつか実行するだけで準備は完了となります。
Django のインストール
まずは、Django をインストールしておきましょう!
Python を利用しているのであれば Django は pip
からインストールすることが可能です。Django をインストールする際の pip
の実行例は下記のようになります。
% python -m pip install django
ウェブアプリの用意
続いてウェブアプリを用意していきます。まずは適当な作業フォルダに移動してから下記コマンドを実行してください。実行すれば selenium_test
というフォルダが作成され、その中にウェブアプリを開発するための様々な Python スクリプトファイルが生成されることになります。
% django-admin startproject selenium_test
次に、上記のコマンドによって生成された selenium_test
フォルダの中に cd
コマンドで移動します。
% cd selenium_test
そして、移動後に下記のコマンドを実行してください。このコマンドはウェブアプリから利用するデータベースを作成するためのコマンドとなります。
% python manage.py migrate
ウェブアプリ自体の用意は以上で完了です。
本来であれば、上記のようなコマンドを実行した後にウェブアプリの作り込みを行なっていく必要があるのですが、前述でも少し触れた通り今回は Django のウェブアプリに用意される管理画面を利用して Selenium での動作確認を実施していくことになり、管理画面自体は上記のコマンドで既に利用可能となっています。
ログイン用ユーザーの作成
ただし、管理画面にログインするためには事前にユーザーを作成しておく必要があります。そのため、次はログイン用のユーザーの作成を行なっていきます。
先ほどと同様に、selenium_test
フォルダの中で下記のコマンドを実行してください。このコマンドは、Django で開発したウェブアプリの管理画面にログインするためのユーザーを作成するコマンドとなります。
% python manage.py createsuperuser
上記コマンドを実行すれば、ユーザー名とメールアドレスとパスワードの入力が促されることになります。パスワードに関しては、確認用に計2回入力する必要があります。
今回は、これらの情報として下記を入力するようにしてください。メールアドレスは今後は使わないですが、ユーザー名とパスワードに関してはログイン操作を Selenium から実行する際に使用することになります。
- ユーザー名:
Yamadahanako
- メールアドレス:
hanako@example.com
- パスワード:
yh123456
これらの情報の入力後(パスワードに関しては2回入力が必要)、下記のメッセージが表示されればユーザーの作成は完了となります。
Superuser created successfully.
ウェブアプリの起動
最後にウェブアプリを起動させます。先ほどと同様に、selenium_test
フォルダの中で下記のコマンドを実行してください。
% python manage.py runserver
実行すると、下記のようなメッセージが表示されてウェブアプリが起動します。
% python manage.py runserver Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). May 27, 2023 - 10:52:50 Django version 4.0.5, using settings 'selenium_test.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C.
そして、これによってウェブブラウザからウェブアプリの操作を行うことができるようになります。上記コマンドはずっと実行された状態となっているため、コマンドを終了させたい場合は ctrl
+ c
キーの入力を行ってください。コマンドを終了させればウェブアプリも終了することになります。再度ウェブアプリを起動する場合は、上記と同じコマンドを実行すれば良いです。
手動でのウェブアプリの操作
続いて、先ほど用意したウェブアプリを手動で操作していきましょう!
ここで実行した手動での操作を、次のフェーズでは Selenium から実行するようにしていきます。ですので、各種操作を実現するために Selenium でどんな処理を実行する必要があるかを思い浮かべながら操作を行なっていくようにしてください。
ページを開く(手動)
まず、ウェブブラウザを開き、ウェブブラウザの URL バーに下記の URL を指定してください。
http://localhost:8000/admin/
指定すれば、下図のようなログインフォームが表示されると思います。
ログイン操作を行う(手動)
このログインフォームには、先ほど作成したユーザーの情報を入力してください。つまり、Username
フィールドには YamadaHanako
を、Password
フィールドには yh123456
を入力してやれば良いです。入力後、LOG IN
ボタンをクリックしてログインを実施します。
ログインに成功すれば、下の図のようなページに遷移すると思います。このページが Django のウェブアプリにおける管理画面となります。
ユーザー一覧を表示する(手動)
続いて、Users
リンクをクリックしてください。このリンクをクリックすればユーザー一覧が表示されるはずです。
ユーザーを登録する(手動)
続いて、ユーザーの登録を行なっていきます。まずは、ユーザー一覧ページの右上にある ADD USER
ボタンをクリックしてください。
クリックすると、下の図のようなユーザー登録フォームが表示されると思います。
続いて、このフォームの Usename
フィールドに YamadaTaro
を、Password
フィールドと Password confirmation
フィールドの両方に yt123456
を入力して SAVE
ボタンをクリックしてください。
これによりユーザーが登録され、続いてユーザーの詳細情報入力フォームが表示されることになります。ページを下方向にスクロールしていけば、下の図のような Staff status
チェックボックスが表示されるはずなので、このチェックボックスのチェックを ON にしてください。
そして、ページの一番下にある SAVE
ボタンをクリックし、先ほどのチェックボックスの変更内容をユーザーの情報に反映させます。
SAVE
ボタンをクリックすれば、再びユーザー一覧ページが表示されると思います。そして、ユーザー一覧の中に、先ほど登録したユーザーが表示されるようになったことが確認できると思います。また、ユーザーを追加で登録したい場合は、ADD USER
ボタンをクリックして先ほどと同様の手順を踏めば良いことになります。
ユーザーを削除する(手動)
続いて、ユーザーの削除を行なっていきます。ユーザーの削除は、今表示されているユーザー一覧ページから行うことができます。
まず、ユーザー一覧の中から削除したいユーザーを選択します。今回は、先ほど登録した YamadaTaro
を削除するため、YamdaTaro
のチェックボックスをクリックしてチェックを ON にしてください。
続いて、Action
フィールドをクリックし、表示される選択肢の中から Delete selected users
をクリックして選択します。そして、その次に、そのフィールドの右にある Go
ボタンをクリックします。
Go
ボタンをクリックすると、下の図のような確認ページが表示されるため、Yes, I'm sure
ボタンをクリックし、削除を実行しましょう!
そうすると、再びユーザー一覧ページに遷移することになるはずです。そして、先ほど削除したユーザーがユーザー一覧から消えていることが確認できるはずです。
ログアウトする(手動)
最後に管理画面からのログアウトを行なっておきましょう!
ログアウトは、ページの上部にある LOG OUT
リンクをクリックすることで行うことができます。
以上が、Django の管理画面からユーザーの追加や削除を行う一連の流れとなります。次は、ここで行なった操作を Selenium で実現していきたいと思います。
様々な操作を行いましたが、大体どんな処理を実行して行けば良いのかは想像がついているのではないかと思います。
スポンサーリンク
Selenium でのウェブアプリの操作
ということで、先ほど実施した手動での操作を、次は Selenium を利用した Python スクリプトから実行していきたいと思います。
Selenium の使い方 で説明したように、特にページ内の要素の操作を行う際には要素の探索が重要となります。この要素の探索を行う際に、要素を特定するための情報を調べる必要がありますので、Chrome で検証機能を利用しながらスクリプトを実装していくことになります。
ページを開く(Selenium)
まず行うのはページを開く操作になります。このページを開く操作は get
メソッドで実現できましたね!ただし、ウェブブラウザを操作するためには事前に WebDriver
のサブクラスのインスタンスを生成しておく必要があります。また、必要なモジュールの import
も必要です。
そのため、まずは Python スクリプトに下記のような処理を記述することになります。
from selenium import webdriver
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get('http://localhost:8000/admin/')
上記のソースコードでは、まず webdriver.Chrome()
で Chrome と Chrome ドライバを起動し、続いて driver.get('http://localhost:8000/admin/')
で引数に指定した URL を開く処理が Chrome に対して実行されることになります。
ログイン操作を行う(Selenium)
続いてログイン操作を Selenium で実現していきます。
ログインフォームは下の図のようになっており、Username
フィールドには YamadaHanako
を、Password
フィールドには yh123456
を入力する必要があります。そして、その後に LOG IN
ボタンをクリックすることでログインを実現することができます。
取得した要素を操作する で説明したように、文字列の入力は send_key
メソッド、クリックは click
メソッドにより実現できます。ですが、メソッドを実行する前に、操作対象となる要素のインスタンスを find_element
メソッドで取得する必要があります。そして、その取得したインスタンスから send_key
や click
メソッドを実行させることになります。
また、今回は find_element
では基本的に XPath での探索を行なって要素の取得を行うようにしていきたいと思います。
なので、ログイン操作を実現するための処理は、下記のような形式のものになることになります。まずは下記を、先ほど紹介したソースコードの下側に追記してください。
username_field = driver.find_element(by=By.XPATH, value='')
username_field.send_keys('YamadaHanako')
password_field = driver.find_element(by=By.XPATH, value='')
password_field.send_keys('yh123456')
login_button = driver.find_element(by=By.XPATH, value='')
login_button.click()
上記が実行されれば、find_element
で XPath が value
の値と一致する要素を取得し、その取得した要素に対して操作(文字列入力やクリック操作)が行われることになります。
ただし、現状では value
の値が空文字列となっているため、この部分に各要素の XPath を調べ、その XPath 記述する必要があります。
ということで、次は XPath を調べていきたいと思います。
ページ内の要素を取得する でも説明したように、この XPath は Chrome の検証機能を利用すれば簡単に調べることができます。
まず、Chrome でログインフォームを表示してください。前述の通り、下記 URL を URL バーに指定してやれば、ログインフォームを表示することができます(ウェブアプリを起動しておく必要がある点&ログアウトしておく必要がある点に注意してください)。
http://localhost:8000/admin/
続いて、ログインフォームの Username
フィールド(入力欄)を右クリックし、表示される右クリックメニューから 検証
を選択します。
すると、検証機能のタブが Chrome の画面右側に表示され、さらに先ほど右クリックを行った Username
フィールドに対応するタグがハイライトされた状態で表示されていると思います(タグが表示されるのは検証機能の Elements
タブになります)。
続いて、そのタグを右クリックし、表示されるメニューから コピー
を、さらに コピー
を選択することで表示されるメニューから XPath をコピー
を選択してください。これにより、Username
フィールドの XPath がクリップボードにコピーされるはずなので、続いて先ほど示したソースコードにおける下記行の value=''
の '
〜 '
の間に貼り付けを行なってください。
username_field = driver.find_element(by=By.XPATH, value='')
おそらくですが、この貼り付け手順を実施することで、上記の行は次のように変化することになるはずです。
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
以上が、1つの要素の XPath を取得する手順となります。あとは、同様にして Password
フィールドと LOG IN
ボタンの XPath を取得し、ソースコードへの貼り付けを行なってください。
貼り付け後のソースコードは下記のようなものになると思います。使用している Django のバージョン等によって XPath が異なるものになる可能性もあるので、一応自身の手で XPath を貼り付けすることをオススメします。
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys('YamadaHanako')
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password"]')
password_field.send_keys('yh123456')
login_button = driver.find_element(by=By.XPATH, value='//*[@id="login-form"]/div[3]/input')
login_button.click()
以上で、管理画面へのログイン操作を行う処理は完成となります。
ユーザー一覧を表示する(Selenium)
先ほどのログイン操作を行う処理が実行されれば管理画面にログインされることになるため、次は管理画面でユーザーの登録やユーザーの削除を行なっていきましょう!
まず、Selenium から管理画面のトップページにある Users
リンクをクリックしてしてユーザー一覧を表示していきます。
といっても、やることは先ほどとほぼ同じで、Users
リンクの XPath を Chrome からコピーし、そのコピーした XPath の要素を find_element
で探索して取得、さらにはその取得した要素に対してクリック操作を行うような処理を記述してやれば、Users
リンクのクリックを実現することができます。
そして、これらの処理は下記のようなものになると思います。XPath には私が Chrome からコピーしたものを記載していますが、もしかしたら異なる可能性もあるため、念の為自身でコピーしたもので上書きしておいていただいた方が無難だと思います(以降も私が取得した XPath を載せていきますが、同様に自身で Chrome から取得したものに置き換えるようにしてください)。
users_link = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/div/table/tbody/tr[2]/th/a')
users_link.click()
ユーザーを登録する(Selenium)
続いて、ユーザー登録を行なっていきます。ユーザー登録を行う際には、まず先ほどの処理によって表示されるユーザー一覧ページの右上にある ADD USER
ボタンをクリックする必要があります。
このクリック操作に関しては、下記のような処理で実現することができます。
add_user_button = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/ul/li/a')
add_user_button.click()
さらに、ADD USER
ボタンをクリックすればユーザー登録フォームが表示されますので、このフォームの Username
フィールドに YamadaTaro
、Password
フィールドと Password confirmation
フィールドに yt123456
を入力し、その後 SAVE
ボタンをクリックするという一連の操作の実装を行なっていきます。
この辺りもログイン操作時とほとんど同じ処理で実現することができます。具体的には下記のような処理によってユーザー登録を実現することができます。
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys('YamadaTaro')
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password1"]')
password_field.send_keys('yt123456')
password2_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password2"]')
password2_field.send_keys('yt123456')
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
上記のような処理によってユーザーが登録されれば、次はユーザーの詳細情報の設定フォームが表示されることになります。ここでは、Staff status
のチェックボックスを ON に変更し、その後 SAVE
ボタンをクリックして詳細情報の変更の反映を行います。
このチェックボックスの ON / OFF に関してもクリック操作で実現できますので、ここまで行なってきたリンクのクリックやボタンのクリック同様に、click
メソッドを利用することになります。
is_staff_check = driver.find_element(by=By.XPATH, value='//*[@id="id_is_staff"]')
is_staff_check.click()
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
上記の最後の行での SAVE
ボタンのクリックが実行されれば、ユーザーの情報が更新された後にユーザー一覧表示ページに遷移することになります。
ユーザーを削除する(Selenium)
次は、先ほど登録したユーザー YamadaTaro
の削除を行なっていきます。ユーザーの削除は、ユーザー一覧の中で削除したいユーザーにチェックを入れ、
Action
リストの中から Delete selected users
を選択したのちに Go
ボタンをクリックすることで実現することができます。
これも今まで通りのやり方で Selenium からの操作を実現することはできるのですが、注意点があるのでその点について説明したいと思います。
注意点とは、ユーザー一覧に表示されるユーザーの順番になります。この Django の管理画面においては、デフォルトではユーザー一覧に表示されるユーザーはユーザー名に対してアルファベット順に並んでいます。最初に createsuperuser
コマンドで YamadaHanako
を作成し、管理画面では YamadaTaro
を作成したため、ユーザー一覧には上側に YamadaHanako
、下側に YamadaTaro
が表示されることになります。
この場合、YamadaTaro
のチェックボックスの XPath は下記のようなものになると思います。
//*[@id="result_list"]/tbody/tr[2]/td[1]/input
ですが、createsuperuser
コマンドで作成するユーザーのユーザー名に YamadaTaro
よりもアルファベット順的に遅い名前、例えば Zack
などを設定していた場合、ユーザー一覧には YamadaTaro
が上側に表示されることになります。
そして、この場合、YamadaTaro
のチェックボックスの XPath は下記のようなものになります。
//*[@id="result_list"]/tbody/tr[1]/td[1]/input
前述で示した YamadaTaro
のチェックボックスの XPath では tr[2]
であった部分が tr[1]
に変化していることが確認できると思います。また、この場合の Zack
のチェックボックスの XPath は下記となり、これが前述の YamadaTaro
の XPath と一致していることになります。
//*[@id="result_list"]/tbody/tr[2]/td[1]/input
つまり、YamadaTaro
というユーザーを削除しようと思ってチェックボックスの XPath を find_element
メソッドの value
引数に指定していたとしても、他のユーザーのユーザー名によっては、その XPath が他のユーザーのチェックボックスに対応している可能性があります。そして、この場合、YamadaTaro
を削除しようとしているのに他のユーザーを削除してしまうことになります。
ここで重要な点は、あくまでも XPath は HTML の構造やタグの位置によって決定される情報であるという点になります。したがって、状況によって HTML の構造や要素の位置が変化してしまうような場合、その状況によっては Selenium で実現したい操作を行えないようなケースがあります。例えば前述のユーザー一覧に関しては、ユーザーの登録状況によって削除したいユーザーのチェックボックス要素の位置が変化することになるため、意図しないユーザーの削除が実行されてしまう可能性があります。
もちろん、今回は登録済みのユーザーが YamadaHanako
と YamadaTaro
の2人であることを前提としているため、XPath での探索で YamadaTaro
のチェックボックスを取得すれば上手く動作するのですが、逆に言えば、その前提が崩れると上手く動作しなくてしまうことになります。これだと応用性が低く使い勝手が悪いです。
では、ユーザーの登録状況に関わらず、YamadaTaro
を確実に削除するにはどうすれば良いでしょうか?
やり方は様々ありますが、今回は YamadaTaro
というユーザー名を持つユーザーを削除しようとしているのですから、このユーザー名を頼りにチェックボックス要素の取得を行なうことで確実に YamadaTaro
を削除することができます。
まず、この管理画面のユーザー一覧の HTML の構造に着目すると、このユーザー一覧は下の図のような列数 6
のテーブルとして表現されています。そして、このテーブルの各行に各ユーザーの情報が格納されて表示されるようになっています。
この、テーブルにおける行は、HTML としては tr
タグで表現されます。つまり、1つの <tr> 〜 </tr>
の中に一人のユーザーの情報が格納されています。さらに、行の中の各要素は td
や th
タグで表現されます。実際に、この tr
タグの中身を Chrome の検証機能で表示した結果が下の図となります。
そして、この 1
つ目の th
タグの中にユーザー名が存在し、さらに 1
つ目の td
タグの中に削除対象を選択するためのチェックボックスが存在しています。
したがって、このテーブルの中の tr
タグの要素を1つ1つ取得し、各 tr
タグの要素の 1
つ目の th
タグの本文が YamadaTaro
であるかどうかをまず判断し、判断結果が Yes の場合に 1
つ目の td
タグの中のチェックボックスに対してクリック操作を行うようにすれば、確実に YamadaTaro
のチェックボックスのみを ON とすることができます。
では、このような処理はどうやって実現できるのか?について考えていきたいと思います。先程も紹介しましたが、各ユーザーのチェックボックスの XPath は下記のような形式のものになっています。
//*[@id="result_list"]/tbody/tr[1]/td[1]/input //*[@id="result_list"]/tbody/tr[2]/td[1]/input
ここまでの解説を踏まえると、上記の XPath は次のようなものであると考えられます。
まず、上記における tr[1]
と tr[2]
部分はテーブルの各行を表しています。tr[1]
が1行目で、一人目のユーザーの情報を表示しており、tr[2]
が2行目で、二人目のユーザーの情報を表示しています。
まず取得すべき要素は、これらの tr
要素となります。ただし、ここで取得したいのはテーブル内の全ての tr
要素となるため、複数の要素が取得できるように find_elements
メソッドを利用します。
そして、下記のように引数を指定して find_elements
メソッドを実行します。
trs = driver.find_elements(by=By.XPATH, value='//*[@id="result_list"]/tbody/tr')
ポイントは、指定している XPath における最後の tr
部分になります。
Chrome からコピーされる XPath は、その要素を一意に特定するための情報であるため、tr[1]
や tr[2]
のようにタグ名に対してインデックスが指定されるようになっています。XPath において、インデックスは 1
から始まります。
このようなインデックスの指定により、複数の同種類のタグの要素の中から1つを探索することができるのですが、1つのみではなく全ての要素を取得したい場合は、上記のように value
にはインデックスを指定せずに find_elements
を実行するようにしてやれば良いです。
上記の場合であれば、//*[@id="result_list"]/tbody/
という XPath に対応する要素の中の全ての tr
要素が取得されることになります。ちなみに、ワイルドカードを利用して同様の処理を行うことも可能です。ワイルドカードを利用した場合は、value
に //*[@id="result_list"]/tbody/tr[*]
を指定することになります。これでも同じ結果が得られます。
さらに、find_elements
では取得した各要素が格納されたリストが返却されることになるので、このリストから1つ1つ要素を取得し、その要素の中の th
要素の本文が YamadaTaro
であるかどうかを確認していくことになります。この際には、tr
要素の中から th
要素を取得することになるため、下記のように for
文の中で th
要素の取得を行う必要があります。この時は 1
つ目の th
要素を取得したいため、value
としては th[1]
のようにインデックスを指定して find_element
によって取得を行う必要があります。
trs = driver.find_elements(by=By.XPATH, value='//*[@id="result_list"]/tbody/tr')
for tr in trs:
th = tr.find_element(by=By.XPATH, value='th[1]')
if th.text == 'YamadaTaro':
このように、find_element
は driver
からだけではなく、find_element
や find_elements
で取得した要素からも実行することが可能です(find_elements
も同様です)。そして、これにより、特定の要素を段階的に絞り込んで取得することが可能となります。
上記のような処理により、th[1]
の本文(text
データ属性)が 'YamadaTaro'
と一致する tr
要素を見つけ出すことができるようになります。あとは、'YamadaTaro'
と一致する tr
要素が見つかった際に、その tr
要素の持つ 1
つ目の td
の中の input
要素をクリックしてやれば良いことになります。
trs = driver.find_elements(by=By.XPATH, value='//*[@id="result_list"]/tbody/tr')
for tr in trs:
th = tr.find_element(by=By.XPATH, value='th[1]')
if th.text == 'YamadaTaro':
check_box = tr.find_element(by=By.XPATH, value='td[1]/input')
check_box.click()
上記の処理によって、YamadaTaro
のチェックボックスが ON にされるようになるため、あとは Action
リストから Delete selected users
をクリックして選択し、Go
ボタンを押せば良いだけです。これらの要素の位置はユーザーの登録状況に関わらず同じ場所に存在するため、単に XPath から探索を行えば良いです。
ただし、Action
リストの Delete selected users
の選択肢はページ上に表示されていないため、検証機能によって表示される HTML の中から該当するタグを見つけ出し、そのタグを右クリックして XPath をコピーする必要があります。また、実際に手作業でユーザーを削除する場合は、一度 Action
リストをクリックして選択肢を表示し、その後に Delete selected users
をクリックすることになるのですが、Selenium の場合は Action
リストのクリックを行わずに直接 Delete selected users
をクリックするのでも問題ありません。
手作業の時に Action
リストをクリックする必要があったのはページ上に表示されていない選択肢 Delete selected users
を表示するためです。が、HTML 上には Delete selected users
がページ表示時から存在していますので、わざわざページ上に表示するためのクリック操作は必ずしも行う必要はないです(必須ではないだけで、別に行なっても良いです)。
実際に XPath をコピーして上記の処理を実装したソースコードは次のようなものになります。
delete_selected_users = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/label/select/option[2]')
delete_selected_users.click()
go_button = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/button')
go_button.click()
上記の処理によって Go
ボタンがクリックされれば、次は削除の確認ページに遷移することになります。ここでは Yes, I'm sure
ボタンのクリックを行うことになります。
ただ、ここもユーザー一覧から削除するユーザーを選んだ時と同様の点に注意が必要となります。今回は YamadaTaro
の一人のみを削除するため問題はないのですが、複数のユーザーを削除しようとした場合、その削除対象にユーザーの数によって Yes, I'm sure
ボタンの XPath が変化することになります。そのため、複数人のユーザー削除に対応しようと思うと少し工夫が必要になります。
この Yes, I'm sure
ボタンの XPath は YamadaTaro
の一人のみを削除しようとした場合は下記のようになります。
//*[@id="content"]/form/div/input[4]
それに対し、4人のユーザーを削除しようとした場合は下記のようになります。
//*[@id="content"]/form/div/input[7]
要は、XPath の最後の input
の添字が削除しようとしてるユーザーの人数 +3
になることになります。これはつまり、削除するユーザーの数だけ Yes, I'm sure
ボタンよりも上側に input
要素が追加されていることを示しています。
ただ、幸いなことに、input
要素が追加されのは Yes, I'm sure
ボタンよりも上側のみです。つまり、先頭の input
要素の位置から考えると Yes, I'm sure
ボタンの位置が削除するユーザーの数によって変化することになりますが、末尾の input
要素の位置から考えると Yes, I'm sure
ボタンの位置は変化しません。もっと言えば、Yes, I'm sure
ボタンは常に input
要素の中の末尾に存在します(実は、隣にある No, take me back
ボタンは Yes, I'm sure
ボタン同様に input
要素の見た目をしていますが、実態はただのリンクです)。
であれば、XPath の input
のインデックスには末尾を示すものを指定してやれば良さそうです。
そして、XPath では末尾の要素を指定するための last()
が利用可能です。これは、同列に並んだ要素の中の末尾のものを指定する関数となります。したがって、Yes, I'm sure
ボタンを探索する際には、下記の XPath を指定してやれば良いことになります。
//*[@id="content"]/form/div/input[last()]
そして、この考え方に基づいた Yes, I'm sure
ボタンのクリック操作は下記のような処理で実現することができます。
sure_button = driver.find_element(by=By.XPATH, value='//*[@id="content"]/form/div/input[last()]')
sure_button.click()
もちろん実現方法は他に持って、削除するユーザーの選択を行った時のように、全ての input
要素を取得し、その中から本文が Yes, I'm sure
であるものを見つけ出すのでも良いです。とにかく大事なのは、目当ての要素を1つに特定できるように要素の探索を行うことであり、具体的な方法は何でも良いと思います。
ログアウトを行う(Selenium)
この章の最後としてログアウトを行なっていきたいと思います。
ログアウトはページ上部の LOG OUT
リンクのクリックにより実現できます。
そして、これは LOG OUT
リンクの要素を取得したのちにクリック操作を行えば良いだけです。
logout_link = driver.find_element(by=By.XPATH, value='//*[@id="user-tools"]/a[3]')
logout_link.click()
全体のソースコード
ここまでのまとめの意味も込めて、紹介してきたソースコードを1つにまとめたものを下記に示しておきます。
from selenium import webdriver
from selenium.webdriver.common.by import By
# ブラウザの起動
driver = webdriver.Chrome()
# 管理画面の表示
driver.get('http://localhost:8000/admin/')
# ログイン
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys('YamadaHanako')
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password"]')
password_field.send_keys('yh123456')
login_button = driver.find_element(by=By.XPATH, value='//*[@id="login-form"]/div[3]/input')
login_button.click()
# ユーザー一覧表示
users_link = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/div/table/tbody/tr[2]/th/a')
users_link.click()
# ユーザー追加
add_user_button = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/ul/li/a')
add_user_button.click()
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys('YamadaTaro')
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password1"]')
password_field.send_keys('Taro12345')
password2_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password2"]')
password2_field.send_keys('Taro12345')
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
is_staff_check = driver.find_element(by=By.XPATH, value='//*[@id="id_is_staff"]')
is_staff_check.click()
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
# ユーザーの削除
trs = driver.find_elements(by=By.XPATH, value='//*[@id="result_list"]/tbody/tr')
for tr in trs:
th = tr.find_element(by=By.XPATH, value='th[1]')
if th.text == 'YamadaTaro':
check_box = tr.find_element(by=By.XPATH, value='td[1]/input')
check_box.click()
delete_selected_users = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/label/select/option[2]')
delete_selected_users.click()
go_button = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/button')
go_button.click()
sure_button = driver.find_element(by=By.XPATH, value='//*[@id="content"]/form/div/input[last()]')
sure_button.click()
# ログアウト
logout_link = driver.find_element(by=By.XPATH, value='//*[@id="user-tools"]/a[3]')
logout_link.click()
# ブラウザの終了
driver.quit()
実行すれば、手動で操作した時と同様に、ログイン操作が行われたのちにユーザーの追加とユーザーの削除が実行され、最後にログアウトが行われたのちにブラウザが終了することになります。
実行時の注意点としては、この管理画面では同じユーザー名のユーザーの作成は不可である点が挙げられます。このスクリプトでは YamadaTaro
というユーザー名のユーザーを作成するため、既に YamadaTaro
が作成されている状態で実行すると途中で例外が発生して処理が終了することになります。
応用例1:操作のループ
また、上記の各種操作を関数化することで、複数のユーザーをループで一気に登録するようなことも可能となります。その例が下記となり、このスクリプトでは 20
人のユーザーの登録を行い、最後に YamadaHanako
以外のユーザーを削除する処理を行なっています。
from selenium import webdriver
from selenium.webdriver.common.by import By
def login(username, password):
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys(username)
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password"]')
password_field.send_keys(password)
login_button = driver.find_element(by=By.XPATH, value='//*[@id="login-form"]/div[3]/input')
login_button.click()
def show_users():
users_link = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/div/table/tbody/tr[2]/th/a')
users_link.click()
def add_user(username, password, is_staff):
add_user_button = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/ul/li/a')
add_user_button.click()
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys(username)
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password1"]')
password_field.send_keys(password)
password2_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password2"]')
password2_field.send_keys(password)
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
if is_staff:
is_staff_check = driver.find_element(by=By.XPATH, value='//*[@id="id_is_staff"]')
is_staff_check.click()
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
def delete_users():
trs = driver.find_elements(by=By.XPATH, value='//*[@id="result_list"]/tbody/tr')
for tr in trs:
th = tr.find_element(by=By.XPATH, value='th[1]')
if th.text != 'YamadaHanako':
check_box = tr.find_element(by=By.XPATH, value='td[1]/input')
check_box.click()
delete_selected_users = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/label/select/option[2]')
delete_selected_users.click()
go_button = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/button')
go_button.click()
sure_button = driver.find_element(by=By.XPATH, value='//*[@id="content"]/form/div/input[last()]')
sure_button.click()
def logout():
logout_link = driver.find_element(by=By.XPATH, value='//*[@id="user-tools"]/a[3]')
logout_link.click()
# ブラウザの起動
driver = webdriver.Chrome()
# 管理画面の表示
driver.get('http://localhost:8000/admin/')
login('YamadaHanako', 'yh123456')
show_users()
for i in range(20):
username = 'YamadaTaro_' + str(i)
add_user(username, 'yt123456', True)
delete_users()
logout()
# ブラウザの終了
driver.quit()
ウェブアプリの動作確認を行う際、事前に複数のユーザーを登録した状態で動作確認を実施したいような場合も多いと思いますので、そのような時に上記のスクリプトのユーザーを作成する処理の部分が利用できると思います。
このように、1つの対象に対する操作を Selenium で実現できるようにしてやれば、ループを利用して拡張を行うことで自動的に複数の対象に対して操作を実施できるようなスクリプトを簡単に実現することができます。
応用例2:スクリーンショット撮影
また、Selenium からはページのスクリーンショットを撮影することも可能です。
下記は各種操作を行う前後にスクリーンショットを撮影する例になります。実行すると多くの画像が保存されることになるので、その点にはご注意ください。また、ヘッドレスモードでウェブブラウザを起動するようにしているため、実行してもウェブブラウザは画面上に表示されません。が、スクリーンショットはバッチリ撮影されていくはずです。
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.options import Options
def login(username, password):
driver.save_screenshot('before_login.png')
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys(username)
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password"]')
password_field.send_keys(password)
login_button = driver.find_element(by=By.XPATH, value='//*[@id="login-form"]/div[3]/input')
login_button.click()
driver.save_screenshot('after_login.png')
def show_users():
driver.save_screenshot('before_show_users.png')
users_link = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/div/table/tbody/tr[2]/th/a')
users_link.click()
driver.save_screenshot('after_show_users.png')
def add_user(username, password, is_staff):
driver.save_screenshot('before_add_user_{}.png'.format(username))
add_user_button = driver.find_element(by=By.XPATH, value='//*[@id="content-main"]/ul/li/a')
add_user_button.click()
username_field = driver.find_element(by=By.XPATH, value='//*[@id="id_username"]')
username_field.send_keys(username)
password_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password1"]')
password_field.send_keys(password)
password2_field = driver.find_element(by=By.XPATH, value='//*[@id="id_password2"]')
password2_field.send_keys(password)
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
if is_staff:
is_staff_check = driver.find_element(by=By.XPATH, value='//*[@id="id_is_staff"]')
is_staff_check.click()
save_button = driver.find_element(by=By.XPATH, value='//*[@id="user_form"]/div/div/input[1]')
save_button.click()
driver.save_screenshot('after_add_user_{}.png'.format(username))
def delete_users():
trs = driver.find_elements(by=By.XPATH, value='//*[@id="result_list"]/tbody/tr')
for tr in trs:
th = tr.find_element(by=By.XPATH, value='th[1]')
if th.text != 'YamadaHanako':
driver.save_screenshot('before_check_user_{}.png'.format(th.text))
check_box = tr.find_element(by=By.XPATH, value='td[1]/input')
check_box.click()
driver.save_screenshot('after_check_user_{}.png'.format(th.text))
driver.save_screenshot('before_delete_users.png')
delete_selected_users = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/label/select/option[2]')
delete_selected_users.click()
go_button = driver.find_element(by=By.XPATH, value='//*[@id="changelist-form"]/div[1]/button')
go_button.click()
sure_button = driver.find_element(by=By.XPATH, value='//*[@id="content"]/form/div/input[last()]')
sure_button.click()
driver.save_screenshot('after_delete_users.png')
def logout():
driver.save_screenshot('before_logout.png')
logout_link = driver.find_element(by=By.XPATH, value='//*[@id="user-tools"]/a[3]')
logout_link.click()
driver.save_screenshot('after_logout.png')
options = Options()
options.add_argument('--headless')
# ブラウザの起動
driver = webdriver.Chrome(options=options)
# 管理画面の表示
driver.get('http://localhost:8000/admin/')
login('YamadaHanako', 'yh123456')
show_users()
for i in range(20):
username = 'YamadaTaro_' + str(i)
add_user(username, 'yt123456', True)
delete_users()
logout()
# ブラウザの終了
driver.quit()
Selenium で操作を行わせると目にも止まらぬスピードで操作が実行されていくため、何が行われているかが把握しづらいですが、各種操作の前後でスクリーンショット撮影を行うようにしておけば、後から撮影したスクリーンショットを調べ、意図した通りの操作が行われているかどうかを確認するようなこともできます。
まとめ
このページでは Python からの Selenium の使い方について、特にウェブブラウザ・ウェブページへの操作に焦点を当てて解説を行いました!
基本的な Selenium の利用手順は下記となります。
WebDriver
のサブクラスのインスタンスを生成する- ウェブブラウザのドライバとウェブブラウザが起動する
- ページを表示する
- ページ内の要素を取得する
- 取得した要素に対して操作を行う
(3. と 4. は必要な分だけ繰り返す) - ウェブブラウザを終了させる
特に、Selenium からウェブブラウザを操作する際にポイントになるのが要素を取得する点になると思います。そして、この要素を取得する際には要素の探索条件をうまく設定する必要があり、ここが Selenim を扱う上で一番難しいところになるかと思います。
ですが、Chrome 等の検証機能を利用すれば、要素を特定するための条件、例えば XPath などは簡単に取得することができます。そのため、Selenium でウェブブラウザの操作を行う際にはこういった機能を利用することをオススメします!
また、Selenium でのウェブブラウザの操作を応用することで、手作業で行っていたウェブアプリの動作確認も自動的に実行することができるようになります。是非、このページで解説した内容を活かして、業務や作業の自動化・効率化に取り組んでいただければと思います!