3

I am very new to Ruby and Selenium.

I am trying to write a script that will open a web page (not a page I run), look through the list of items there, and click on the "Details" link for the item that meets certain criteria. A very stripped-down version of the page is:

<div class="list">

<div class="item">
    <div class="description">Cat</div>
    <div class="price">$3.00</div>
    <div class="detailslink">
        <a href="http://a.htm">Details</a>
    </div>
</div>

<div class="item">
    <div class="description">Dog</div>
    <div class="price">$4.00</div>
    <div class="detailslink">
        <a href="http://b.htm">Details</a>
    </div>
</div>

<div class="item">
    <div class="description">Cat</div>
    <div class="price">$4.00</div>
    <div class="detailslink">
        <a href="http://c.htm">Details</a>
    </div>
</div>

<div class="item">
    <div class="description">Bird</div>
    <div class="price">$3.00</div>
    <div class="detailslink">
        <a href="http://d.htm">Details</a>
    </div>
</div>

An example of what I would like to do is click on the "Details" link for the most expensive animal that is NOT a dog. I am guessing that I would create an array of all the "item" class elements with find_elements that don't include the word "dog", find the index of highest price within that array, and click on the link in the corresponding "detailslink", but I do not know how to write that out in Ruby.

Ideally it would also refresh every 30 seconds if there were no list items that met the criteria (there were no "item" divs within the "list" div, or all of the "list" divs contained Cat). Here is what I have so far (I know it is missing a lot!):

require "selenium-webdriver"
browser = Selenium::WebDriver.for :chrome
browser.get "http://list.htm"
for i in 0..1
    items = browser.find_elements(:class=>"item")
    #Do testing here. If there are non-cats, get the index of the max.
        break
    end
    sleep(30)
    browser.get "http://list.htm"
    redo
end
#find the nth element based on the test above
browser.find_element(:class, "detailslink")[index].click

Any help would be greatly appreciated!

3 Answers 3

5

For those of us using Ruby, there is a decent sheet in gist for find_element and find_elements usage.

https://gist.github.com/huangzhichong/3284966#file-selenium-webdriver-cheatsheet-md

Sign up to request clarification or add additional context in comments.

1 Comment

Please put the relevant parts of the link in your answer; so that if the link goes down in future, you answer would remain useful.
2

I don't think there is generic solution, but for your specific example:

browser = Selenium::WebDriver.for :firefox
browser.navigate.to 'C:\Scripts\Misc\Programming\Selenium-Webdriver\test.htm'

# Refresh the page until there is at least 1 dog
items = browser.find_elements(:class=> 'item')
dog_items = items.find_all{ |item| item.find_element(:class => 'description').text == 'Dog' }   
while dog_items.length == 0
  sleep(30)
  browser.navigate.refresh
  items = browser.find_elements(:class=> 'item')
  dog_items = items.find_all{ |item| item.find_element(:class => 'description').text == 'Dog' }     
end

# Select the dog with the greatest price
most_expensive = dog_items.sort_by{ |dog| dog.find_element(:class => 'price').text.delete('$').to_f }.last

# Click the selected dog
most_expensive.find_element(:css => '.detailslink a').click

Comments

0

I have never really tried to use Selenium but with nokogiri it would be something like this (I made it more verbose for clarity obviously some of the methods could be chained)

require 'open-uri'
require 'nokogiri'
doc = Nokogiri::HTML(open("http://list.htm"))
items = doc.css(".item")
non_dog_items = items.reject{|item| item.children.css(".description").text == "Dog"}
most_expensive_non_dog_item = non_dog_items.max_by{|item| item.children.css(".price").text.gsub("$",'').to_f}
link_to_most_expensive_non_dog_item = most_expensive_non_dog_item.css(".detailsLink a").attributes["href"].value
#=> "http://c.htm"

Only issue with this is that if 2 of your items have the same price so max_by with return the first item with the highest price.

You could also return all items as a hash and then deal with the hash only

require 'open-uri'
require 'nokogiri'

doc = Nokogiri::HTML(open('/scripts/test.html'))
items = doc.css(".item").reject{|item| item.css(".description").text == "Dog"}
items_hash = items.map do |item|
      {description: item.css(".description").text,
       price: item.css(".price").text.gsub("$",'').to_f,
       link: item.css(".detailsLink a").attributes["href"].value
      }
    end
#=> [{:description=>"Cat", :price=>3.0, :link=>"http://a.htm"},{:description=>"Cat", :price=>4.0, :link=>"http://c.htm"},{:description=>"Bird", :price=>3.0, :link=>"http://d.htm"}]

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.