株式会社クリアコード > ククログ

ククログ


WebDriver APIを使ったLua用のWebブラウザー自動操作ライブラリー LuaWebDriver

WebDriver APIを使ってWebブラウザーを自動操作できるLuaのライブラリーを開発しました。LuaWebDriverといいます。
これは、クリアコードが株式会社セナネットワークス様からの発注を受けて開発したライブラリーです。MITライセンスで公開しています。

今のところ、操作できるWebブラウザーはFirefoxのみです。
LuaWebDriverはWebDriver APIを使って、LuaからFirefoxを操作することができます。Firefoxはデフォルトでヘッドレスモードで起動します。(GUIでの起動もできます。)

Webブラウザーを利用してWebサイトをレンダリングするため、JavaScriptを使用して動的に生成されるWebページをスクレイピングすることや、HTMLのパーサーライブラリ等で解釈できないような正しくないHTMLで書かれたWebページのスクレイピング等に使用できます。(正しくないHTMLで書かれたWebページもWebブラウザーはなんとか表示するため。)
また、Webブラウザーを操作できるので、ログインが必要なページに対して、ログインし、ログイン後のWebページをスクレイピングするようなこともできます。

インストール方法

LuaWebDriverは、LuaRocksで公開しており、luarocksコマンドを使ってインストールできます。
また、Firefoxを操作するためにgeckodriverを使っているため、本ライブラリーの他にgeckodriverのインストールも必要です。

例えば、CentOS7では、以下のようにインストールします。

% yum install -y gcc gcc-c++ firefox lua-devel luajit-devel luarocks make openssl-devel
% curl -L -O https://github.com/mozilla/geckodriver/releases/download/v0.23.0/geckodriver-v0.23.0-linux64.tar.gz
% tar xf geckodriver-v0.23.0-linux64.tar.gz -C /usr/local/bin
% chmod +x /usr/local/bin/geckodriver
% sudo luarocks install web-driver

CentOS7以外のインストール方法は、LuaWebDriverのドキュメントのインストールを参照してください。
LuaWebDriverは、CentOS7の他にmacOSに対応しています。

基本的な使い方

LuaWebDriverを使ってFirefoxを操作するには、web-driver.Firefoxクラスのオブジェクトが必要です。
web-driver.Firefoxクラスのオブジェクトは以下のように作成します。

local Firefox = require("web-driver/firefox")
local firefox = Firefox.new()

web-driver.Firefoxクラスのオブジェクト作成時には、様々なオプションが設定できますが、ここでは、わかりやすさのため、オプションは設定せず、全てデフォルト値で実行します。
設定可能なオプションについては、web-driver.Firefoxクラスのリファレンスを参照してください。

web-driver.Firefoxクラスのオブジェクトを作成しました。次は、作成したオブジェクトを使って、Firefoxを起動し、操作します。
Firefoxの起動と操作は、web-driver.Firefox:start_session()を使って行います。

web-driver.Firefox:start_session()は引数にコールバック関数を指定でき、LuaWebDriverは、Firefox起動後、引数に指定されたコールバック関数を実行します。このweb-driver.Firefox:start_session()の引数に与えるコールバック関数内にFirefoxを操作して実行したい処理を実装します。

例えば、指定したURLのWebサイトへアクセスする場合は以下のように実装します。

local Firefox = require("web-driver/firefox")
local firefox = Firefox.new()

local URL = "https://clear-code.gitlab.io/lua-web-driver/sample/"

-- コールバックの作成とセッションの開始
firefox:start_session(function(session)
  -- 指定したURLのWebサイトへアクセス
  session:navigate_to(URL)
end)

コールバック関数の引数には、起動したFirefoxとのセッションがweb-driver.Sessionクラスのオブジェクトとして渡されます。
このオブジェクトを使って、ブラウザーの操作を実装します。
Webサイトへのアクセスは、web-driver.Session:navigate_to()を使って行います。このメソッドの引数にアクセスしたいWebサイトのURLを指定すると、そのURLへアクセスできます。

Webサイトへのアクセス以外の操作については、web-driver.Sessionクラスのリファレンスに記載がありますので、合わせて参照してください。

主な機能

LuaWebDriverの主な機能を紹介します。
LuaWebDriverを使うとLuaで以下のようなことができます。

Webサイトへのログイン、ページ内のリンククリック

ここでは、ログインが必要なWebサイトへアクセスし、ログインを実施、ログイン後のページ内のリンクをクリックしてWebページを移動、移動後のページの要素のテキストを取得する例を示します。
少し複雑な例ですが、Webサイトの操作によく使う機能を紹介できるので、このような例にしました。

ログインの実行やリンククリックを行うには、特定のフォームへのテキスト入力、ボタン操作、リンクのクリック操作が必要です。
LuaWebDriverでは、これらを、web-driver.Session:css_selectweb-driver.ElementSet:send_keys()web-driver.ElementSet:click()web-driver.Session:link_search()というメソッドで実現します。

具体的な使い方は、以下の実装例を使って説明します。

local Firefox = require("web-driver/firefox")
local firefox = Firefox.new()

local URL =
  "https://clear-code.gitlab.io/lua-web-driver/sample/move.html"

-- コールバックの作成とセッションの開始
firefox:start_session(function(session)
-- ログインが必要なページへアクセス
  session:navigate_to(URL)

-- Webサイト内のフォームを取得
  local form = session:css_select('form')
-- ユーザー名を入力するためのフォームを取得
  local text_form = form:css_select('input[name=username]')
-- フォームにユーザー名を入力
  text_form:send_keys("username")
-- パスワードを入力するためのフォームを取得
  local password_form = form:css_select('input[name=password]')
-- フォームにパスワードを入力
  password_form:send_keys("password")

-- ユーザー名とパスワードを送信するためのボタンを取得
  local button = form:css_select("input[type=submit]")
-- ユーザー名とパスワードを送信
  button:click()

-- リンク操作をするための要素オブジェクトを取得
  local link = session:link_search("1")
-- リンクをクリック
  link:click()
  local elements = session:css_select("p")
-- 取得した要素のテキストを取得
  print(elements:text())
-- 1
end)
ログイン

まずは、web-driver.Session:css_select()を使って、ユーザー名を入力するフォームを取得します。 web-driver.Session:css_select()は、CSSセレクターを用いて取得したい要素を指定できます。上記例では、input[name=username]としているので、name属性がusernameとなっているinput要素を取得します。

取得した結果は、web-driver:ElementSetクラスのオブジェクトとして返ってきます。
返ってきたオブジェクトを使って、web-driver:ElementSet:send_keys()を実行します。このメソッドは、取得した要素に対して指定したテキストを入力します。上記例では、取得したinput要素にusernameという文字列を入力しています。
これで、ユーザー名の入力は完了です。

次にパスワードの入力を実施します。パスワードの入力もユーザー名の入力と同様web-driver.Session:css_select()を使ってinput要素を取得し、取得したinput要素に対して、web-driver.ElementSet:send_keys()を使ってパスワードを入力します。

ユーザー名とパスワードの入力が完了したら、次は、ユーザー名とパスワードを送信するために送信ボタンを押下します。
送信ボタンの押下は、web-driver.Session:css_select()を使って、送信ボタンを取得します。ボタンの押下は、web-driver.ElementSet:click()を使います。

ここまでで、ユーザー名とパスワードを入力し、それらを送信しました。
入力したユーザー名とパスワードに間違いがなければ、ログイン成功し、ログイン後のページヘ遷移します。

リンク先のページへ遷移

次は、ログイン後のページ内のリンクをクリックし、別のページへ遷移します。
ページ内のリンクを取得するには、web-driver.Session:link_search()を使います。このメソッドの引数にa要素のname属性の値を指定します。
上記の例では、リンクテキストが「1」のリンクを取得しています。取得したリンクをクリックするには、web-driver.ElementSet:click()を使います。
これで、リンク先のページへ遷移します。

ページ内のテキストを取得

リンク先のページへ遷移後は、ページ内要素を取得し、その要素のテキストを取得します。
要素の取得は、今までと同様、web-driver.ElementSet:css_select()で取得します。
取得した要素のテキストを取得するには、web-driver.ElementSet:text()を使用します。web-driver.ElementSet:text()は要素のテキストを文字列として返します。
上記の例では、遷移後のページのp要素のテキストを取得し、printを使ってテキストを標準出力に出力しています。

このようにして、LuaWebDriverでは、Webブラウザーを操作し、必要なページや要素へアクセスしその値を取得することができます。
今回の例では、要素の取得にCSSセレクターを使いましたが、XPathなどその他の方法で検索、取得することもできます。
CSSセレクター以外の取得方法については、web-driver.Searchableモジュールのリファレンスに記載しています。

終わりに

LuaWebDriverの基本的な使い方と主な機能を紹介しました。ここで紹介した機能以外にも便利な機能があります。
LuaWebDriverのその他の機能については、以下のドキュメントを参照して下さい。

チュートリアル
リファレンス

このライブラリーは、XMLuaLuaCSと同様株式会社セナネットワークス様からの依頼を受けて開発した受託開発の成果物です。

成果物をフリーソフトウェアとして公開すると、様々なユーザーがライブラリーを使うことによって、いままで気が付かなかったバグを発見できたり、ユーザーからの要望によって、当初想定していなかった、便利な新機能を実装するきっかけとなったり、様々なメリットがあます。

このように成果物の公開によって、ライブラリーの品質も高まるので、お客さんにとっても成果物を公開するメリットがあります。

ご依頼主の株式会社セナネットワークス様には、上記のようなメリットにご理解をいただき、成果を公開できました。ありがとうございます!

2018-11-06

«前の記事: Tokyo WebExtensions Meetup #3 最新記事 次の記事: YoctoでFcitxをビルドする »
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|