find_elements array use question?

53 views
Skip to first unread message

Blue Tyson

unread,
Sep 26, 2016, 4:20:33 PM9/26/16
to Selenium Remote Driver
Hi,

I am probably not understanding exactly the usage context...as I get an array with many elements (there should be lots on the page).  However, I get an error that can't call get_text on an undefined values.  I have tried a lot of things and searching I don't seem to have cracked it.

@checkbox = $driver->find_elements("checkbox","class");
$number_in_array = @checkbox;
print $number_in_array  #>0 when tested;

for my $elem (@checkbox)
{
  #print OUTPUTFILEYEAR $elem . "\n";
  print OUTPUTFILEYEAR $elem->get_text() . "\n";
}

Similarly, to go through and click all the checkboxes, or a subset of, do you approach similarly?

Thanks very much,

bt

Daniel Gempesaw

unread,
Sep 26, 2016, 5:20:03 PM9/26/16
to Selenium Remote Driver

Hi bt,

Hmm, that’s pretty weird. Have you tried printing @checkbox - is there really Selenium::Remote::WebElements inside? If you can provide a reproduction case (an entire perl script and a webpage that causes the error), that would be the most helpful. Otherwise, I probably can't help much; your script looks reasonable enough and I don't have enough information to do anything besides make bad random debugging guesses.

It probably isn’t any help, but the following works as expected over here:

use strict;
use warnings;
use feature qw/say/;
use Selenium::Chrome;

my $c = Selenium::Chrome->new;
$c->get('https://news.google.com');

my @elems = $c->find_elements('titletext', 'class');
say scalar @elems;
say $_->get_text for @elems;

$c->shutdown_binary;

# prints:
# 227
# Clinton, Trump hours away from historic debate battle
# Presidential Debate: New Polls Show Dead Heat Between Trump and Clinton
# Amid Super Bowl-level hype, Clinton and Trump face off in their first blockbuster presidential debate
# What time is the Presidential debate and how can I watch in the UK?
# Analysis: Donald Trump Would Win Election Today Based on Polling
# Clinton must work harder for the young black voters Trump is courting
# First Presidential Debate: Live Coverage
# ...

Good luck!

Message has been deleted

Daniel Gempesaw

unread,
Sep 26, 2016, 8:54:17 PM9/26/16
to Selenium Remote Driver

Similarly, to go through and click all the checkboxes, or a subset of, do you approach similarly?

Whoops, missed this part - but, yes, you’ve got the essence of it 100% correct.

my @elems = $driver->find_elements('checkbox', 'class');
for (@elems) {
    if ($condition) {
        $_->click;
    }
}

Blue Tyson

unread,
Sep 27, 2016, 12:48:07 AM9/27/16
to Selenium Remote Driver
Yes, I did check there were webelements...or at least hash looking things that appeared to be, but I will do it again.

Blue Tyson

unread,
Sep 27, 2016, 12:56:07 AM9/27/16
to Selenium Remote Driver


On Tuesday, 27 September 2016 14:18:07 UTC+9:30, Blue Tyson wrote:
Yes, I did check there were webelements...or at least hash looking things that appeared to be, but I will do it again.

@checkbox = $driver->find_elements("checkbox","class");
  $count = 0;
  for (@checkbox)
  {
    print OUTPUTFILEYEAR $count . "\n";
    print OUTPUTFILEYEAR $_ . "\n";
    print OUTPUTFILEYEAR $_->get_text() . "\n";
    $count++;
  }

gives

0
Selenium::Remote::WebElement=HASH(0x31b97f4)

1
Selenium::Remote::WebElement=HASH(0x31b97e4)

2
Selenium::Remote::WebElement=HASH(0x340c5c4)

3
Selenium::Remote::WebElement=HASH(0x35f59bc)

4
Selenium::Remote::WebElement=HASH(0x35f4624)

5
Selenium::Remote::WebElement=HASH(0x37908dc)

6


etc,

Blue Tyson

unread,
Sep 27, 2016, 1:08:10 AM9/27/16
to Selenium Remote Driver
#!/usr/bin/perl

use Selenium::Firefox;
use warnings;
use Data::Dumper;

my $driver = Selenium::Firefox->new( marionette_enabled => 0, javascript => 1 );

$driver->get("http://bet.hkjc.com/default.aspx?url=/racing/pages/odds_tt.aspx&lang=en&dv=local");

$driver->switch_to_frame("info");

open OUTPUTFILEYEAR, ">$ddrive\\selenium.txt" or die "NO OUTPUT";
print OUTPUTFILEYEAR $driver->get_page_source();
print OUTPUTFILEYEAR "\n";


  @checkbox = $driver->find_elements("checkbox","class");
  $count = 0;
  for (@checkbox)
  {
    print OUTPUTFILEYEAR $count . "\n";
    print OUTPUTFILEYEAR $_ . "\n";
    print OUTPUTFILEYEAR $_->get_text() . "\n";
    $count++;
    $_->click();
  }


$number_in_array = @checkbox;  #at current run, 73

Interestingly, putting the click method in there I get this error...would that cause failing but get_text not do so.  I am not sure how to fix the below.

Error while executing command: getElementText: An element command failed because
 the referenced element is no longer attached to the DOM.: Element is no longer
attached to the DOM at C:/Perl/site/lib/Selenium/Remote/Driver.pm line 313.
 at C:/Perl/site/lib/Selenium/Remote/Driver.pm line 313.

This is the actual example I ran just now.


Thanks again,

bt

Blue Tyson

unread,
Sep 27, 2016, 1:11:01 AM9/27/16
to Selenium Remote Driver
Windows 7 Professional, Firefox 43 for reference.

Daniel Gempesaw

unread,
Sep 27, 2016, 1:37:21 PM9/27/16
to Selenium Remote Driver
> Error while executing command: getElementText: An element command failed because the referenced element is no longer attached to the DOM.: Element is no longer attached to the DOM at C:/Perl/site/lib/Selenium/Remote/Driver.pm line 313. at C:/Perl/site/lib/Selenium/Remote/Driver.pm line 313.

Oh, this error message is more helpful. Apparently you're running into a StaleElementReferenceError. Usually, this happens when the test gets an element via `find_element(s)`, then the page's DOM changes due to AJAX or whatever javascript reasons, and then the test tries to interact with the element even though it's no longer on the page. 

However, your test doesn't seem to be doing anything with the page, so it's surprising that Webdriver can no longer interact with the elements. Well, if you're aware of any javascript or AJAX going on in the page that changes the checkbox elements, that would be the easiest solution. Otherwise, I'll try and look at this more in depth later.

Cheers!

Brandon Brown

unread,
Sep 27, 2016, 2:17:59 PM9/27/16
to Selenium Remote Driver
So as an aside, I've seen this behavior quite a bit in my selenium tests (see my other posts) that have heavy AJAX and javascript going on. I think, though I wouldn't know how to prove, that there is a race condition going on. Even if the find_element and page interaction happen one after the other, I see these errors. Unfortunately most of the sites i'm testing on are private. Daniel recommended wrapping multiple finds and interactions in a Try::Tiny (see my earlier post) to catch the exception. This cuts down on about 98% of these DOM errors but they still do happen which makes me think there is a race condition. Just some thoughts...

Blue Tyson

unread,
Sep 27, 2016, 11:45:55 PM9/27/16
to Selenium Remote Driver
Ok, thanks, I can try that. Selenium::Waiter later tonight, with luck. 

Blue Tyson

unread,
Sep 27, 2016, 11:47:44 PM9/27/16
to Selenium Remote Driver
There are quite a few javascript things involved with that page....there are XML calls that update odds etc. frequently for one thing, is the first I would think of.

Blue Tyson

unread,
Sep 28, 2016, 9:38:26 PM9/28/16
to Selenium Remote Driver
statewide power failure last night...so will have to wait until the weekend to look at this

Blue Tyson

unread,
Sep 30, 2016, 1:18:40 AM9/30/16
to Selenium Remote Driver
I modified as per a suggestion :-

my $clicked = wait_until {@checkbox = $driver->find_elements("checkbox","class") };
if ($clicked)
{

  $count = 0;
  for (@checkbox)
  {
    print OUTPUTFILEYEAR $count . "\n";
    print OUTPUTFILEYEAR $_ . "\n";
    #print OUTPUTFILEYEAR $_->get_text() . "\n";
    $count++;
    $_->click();
  }
}
else
{
    print 'tried for thirty seconds unsuccessfully';
 }


same problem as before, unfortunately

George Baugh

unread,
Nov 28, 2017, 1:25:23 PM11/28/17
to Selenium Remote Driver
One thing I've done when running into persistent DOM strobing in tight loops is modify S::R::D's error handler to re-acquire a target lock on DOM detach errors (basically just re-do the find() call).

Seemed to help out a lot.  I really should add a class with some useful pre-baked error handlers to use based on some of our classes.
Reply all
Reply to author
Forward
0 new messages