[質問] seleniumでページスクロール後のSelenium::WebDriver::Waite 内の判別で、elementが存在するかしないか分からない場合の対処方法

425 views
Skip to first unread message

roswell

unread,
Mar 3, 2018, 11:49:16 PM3/3/18
to 日本Seleniumユーザーコミュニティ
Mac OS High Sierra Version 10.13.2

$ ruby --version
ruby 2.3.3p222 (2016-11-21 revision 56859) [universal.x86_64-darwin17]
$ gem list -l selenium selenium-webdriver nokogiri
*** LOCAL GEMS ***
selenium (0.2.11)
selenium-webdriver (3.9.0)
*** LOCAL GEMS ***
selenium-webdriver (3.9.0)
*** LOCAL GEMS ***
nokogiri (1.8.2, 1.5.6)
$ chromedriver --version
ChromeDriver 2.35.528157 (4429ca2590d6988c0745c24c8858745aaaec01ef)

の環境で、
https://www.justwatch.com/jp
に表示されるビデオのタイトルを取得する Ruby スクリプトを作成しています。


下記のスクリプトで、
element.location_once_scrolled_into_view で、ページスクロール後、
sleep 5 としているところを、wait.until … で置き換えようとしているのですが、…
ページスクロール後、ページにxpathで指定したelementが存在するのかわからないので、適切な処理を書けずにいます。
ページが完全にload出来たか判別する方法があれば、それを用いたいのですが...
良い方法があれば、ご教示いただけますでしょうか?


#! /usr/bin/env ruby
# coding: utf-8

require 'pp'
require 'selenium-webdriver'
require 'nokogiri'

JUSTWATCH_COUNTRY = 'jp'

case JUSTWATCH_COUNTRY
when 'jp'
  url = 'https://www.justwatch.com/jp'
  title_str = 'JustWatch 動画配信 映画 TV番組 検索エンジン'
when 'us'
  url = 'https://www.justwatch.com/us'
  title_str = 'JustWatch - Streaming Search Engine for movies and tv shows'
else
  puts "[ERROR] #{JUSTWATCH_COUNTRY} is not unspported!"
  exit
end

driver = Selenium::WebDriver.for :chrome

# refer http://katsulog.tech/i-do-not-recommend-using-sleep-when-waiting-for-elements/
wait = Selenium::WebDriver::Wait.new(:timeout => 10) 

# When first title seems to be 'JustWatch'
# After title of page is as same as titel_str, we are ready to get the video's title
wait.until do
  driver.get url
  break if driver.title == title_str
end

# after moved video list pages
title_cnt = 1

loop do
  html = driver.page_source

  # parse page by nokogiri
  html_doc = Nokogiri::HTML(html)
  xpath = "//*[@id=\"content\"]/div/div[2]/div[position()>=#{title_cnt}]/title-card/track-title-control/div/div[1]/div/div/a/img"
  elements = html_doc.xpath(xpath)

  title_cnt_1 = elements.size

  if elements.size > 0 then
    puts "***** url         : #{elements.size}"
    puts "***** element.size: #{elements.size}"
    elements.each do |nodeset|
      puts "[#{title_cnt}] #{nodeset.attribute('alt')}"
      title_cnt += 1
    end
  else
    puts "[ERROR] no element xpath:#{xpath}"
    exit
  end

  # refer https://stackoverflow.com/questions/7327858/how-to-scroll-with-selenium
  # find the last element for scrolling next page
  xpath = "//*[@id=\"content\"]/div/div[2]/div[position()=#{title_cnt-1}]/title-card/track-title-control/div/div[1]/div/div/a/img"
  element = driver.find_element(:xpath,xpath)

  # scroll next page
  element.location_once_scrolled_into_view

  if false
    sleep 5
  else
    wait.until do
      xpath = "//*[@id=\"content\"]/div/div[2]/div[position()=#{title_cnt}]/title-card/track-title-control/div/div[1]/div/div/a/img"
      element = driver.find_element(:xpath,xpath)
      puts "&&&&& #{element}"
      break if element.displayed?
    end
  end
  
end

driver.quit

保木本将之

unread,
Mar 4, 2018, 12:38:39 AM3/4/18
to 日本Seleniumユーザーコミュニティ
こんにちは

保木本 ( @oh_rusty_nail ) です。

手元で動かしてみたところ、指定したxpathで要素を取得する箇所で失敗(elements.sizeが0になりエラーが出力される)ため次のように修正しました。
Seleniumを使うのであれば、find_elementsで拾ってくるのが良いと思いました。

- elements = html_doc.xpath(xpath)
+ elements = driver.find_elements(xpath: xpath)

また、Capybaraのfindを使うのであれば明示的な待機処理はいらないので、それも対処の1つだと思います。

一応、ヘッドレスでChromeのオプション設定して確認したので差分書いておきます。

- driver = Selenium::WebDriver.for :chrome
+ caps
= Selenium::WebDriver::Remote::Capabilities.chrome(
+ chrome_options: {
+ args: %w[headless disable-gpu no-sandbox]
+ }
+ )
+ driver = Selenium::WebDriver.for :chrome, desired_capabilities: caps

試してみてください。
よろしくお願いします。



2018年3月4日日曜日 13時49分16秒 UTC+9 roswell:

roswell

unread,
Mar 4, 2018, 5:10:45 AM3/4/18
to 日本Seleniumユーザーコミュニティ

保木本さん

roswellです。
御教示ありがとうございます。

2018年3月4日日曜日 14時38分39秒 UTC+9 保木本将之:

手元で動かしてみたところ、指定したxpathで要素を取得する箇所で失敗(elements.sizeが0になりエラーが出力される)ため次のように修正しました。
Seleniumを使うのであれば、find_elementsで拾ってくるのが良いと思いました。

- elements = html_doc.xpath(xpath)
+ elements = driver.find_elements(xpath: xpath)


ご助言ありがとうございます。
Seleniumだけで処理できる方がいいですね。
勉強になりました。
 
また、Capybaraのfindを使うのであれば明示的な待機処理はいらないので、それも対処の1つだと思います。

Capybara だと待機処理が要らないんですか?
便利そうですね。試してみます。
 

一応、ヘッドレスでChromeのオプション設定して確認したので差分書いておきます。

- driver = Selenium::WebDriver.for :chrome
+ caps
= Selenium::WebDriver::Remote::Capabilities.chrome(
+ chrome_options: {
+ args: %w[headless disable-gpu no-sandbox]
+ }
+ )
+ driver = Selenium::WebDriver.for :chrome, desired_capabilities: caps

試してみてください。 

こちらも、 併せて試してみます。 

保木本将之

unread,
Mar 4, 2018, 7:06:37 AM3/4/18
to 日本Seleniumユーザーコミュニティ
roswell さん

保木本です。

以前は wait_until で待機処理を入れていましたが、v2.0.0以降では削除されて
Implicit Wait (暗黙的な待機)の仕組みが取り入れられたため、明示的な待機を入れる必要はありません。
> Capybara だと待機処理が要らないんですか?

数日前に開催したのですが、Selenium談話会というSlack上での勉強会をやりました。
また、この勉強会に限らずいつでも気軽に質問や意見交換できるスペースですので
ぜひSlackの方にもご参加ください。
詳しくはこちら https://selenium-danwakai.connpass.com/



2018年3月4日日曜日 19時10分45秒 UTC+9 roswell:
Reply all
Reply to author
Forward
0 new messages