Issue
This is a inverse question of
$driver.get_element_by_xpath(....)
Background
I have a series of dynamically generated pages to parse. The target element doesn't have a good locator, xpath, text, or id. However, the neighbor element has a unique text to match. My plan is to locate the neighbor element and use its xpath to come up with the target xpath.
$neighbor_element = $driver.get_element_by_text("unique text"); # or some other way
$neighbor_xpath = $neighbor_element.xpath; # this step is the question
$target_xpath = modify($neighbor_xpath); # this is my function
$target_element = $driver.get_element_by_xpath($target_xpath);
I have searched around. cannot find a function or method to get xpath from an element, Perl or Python.
Update
I apologize that I cannot post the example page because it is owned by a company, but I hope the question is straightforward enough. When I use chrome devtools to inspect, I see the xpath are related
neighbor xpath = //*[@id="lable_ni.dynmic_string 123456"]/lable/span[2]
target xpath = //*[@id="dynmic_string 123456"]
Update2
This the dummy test file
<!DOCTYPE html>
<html>
<head></head>
<body>
<div>
<div id="lable_ni.dynmic_string 123456">
<label id="lable_ni.dynmic_string 123456">
<!-- I use this as neighbour element -->
<span>unique text</span>
</label>
</div>
<div>
<!-- target element is here -->
<textarea id="dynmic_string 123456">target text is here</textarea>
</div>
</div>
</body>
</html>
This is how it looks like
My strategy was to
- find the xpath of "unique text". (this text is known beforehand)
- convert it to the xpath of target text
- get the target text
I stuck at the first step
Solution
Find the parent of that "known-neighbor" then their select child, or children that are next in the list to the known one.
I am a little confused by what is known about the target. The original text says that
The target element doesn't have a good locator, xpath, text, or id.
but the edit shows
target xpath = //*[@id="dynmic_string 123456"]
Since there's got to be some way to tell I'll take it as a fact that something is known about the target. Another way would be to get all children (so, all siblings) and browse through them and locate the ones next to the known one.
Here is an example with Perl. For this very page, take that known-neighbor to be a <p>
with some text and find the target which is a sibling <p>
and which has some given text in it. (As an equivalent of finding a sibling with that id
given in the question's edit.)
use warnings;
use strict;
use feature 'say';
use Selenium::Chrome;
my $url_SO = q(https://stackoverflow.com/questions/71849162/)
. q(how-to-find-the-neighbour-element-of-an-active-element-)
. q(using-selenium-with-pytho);
my $drv = Selenium::Chrome->new( 'extra_capabilities' =>
{ 'goog:chromeOptions' => { args => [ 'headless' ] }} );
$drv->get($url_SO);
say "\nPage title: ", $drv->get_title, "\n";
# Our "neighbor": <p> with text 'This is...'
# Get parent with: 'element-spec/..'
my $parent = eval {
$drv->find_element(
'//p[text()="This is a inverse question of"]/..') };
if ($@) { die "Error on <p>'s parent: $@" }
say "known-<p>'s parent tag: ", $parent->get_tag_name;
say "known-<p>'s parent text:";
say '-'x50, "\n", $parent->get_text, "\n", '-'x50;
# Target: <p> with text that contains word 'searched'
my $tgt = eval {
$drv->find_child_element(
$parent, q(./p[contains(text(), 'searched')]) ) };
if ($@) { die "find-child error: $@" }
say "target text: ", $tgt->get_text;
This does as expected. I can't really post a closer match to the question because not much is given. If I misunderstood that that shown id
of the target is known then use find_child_elements on the $parent
and go down the list probing for the known neighbor. The target should be the one before or after (and you better know which :)
If the target isn't in fact a true sibling, but is rather a child of a further ascendant (than the immediate parent), the xpath expressoin can go up the hierarchy with the additional /../..
(etc).
This uses the (server-less) Selenium::Chrome, with methods in Selenium::Remote::Driver and Selenium::Remote::WebElement
(It should be possible to do the whole known-element->parent->child thing with a single XPath expression, or perhaps even look directly for siblings, I'll look once there's time.)
Answered By - zdim
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.