We can get a parent of a selenium element using xpath, by
par_element = element.find_element_by_xpath('..')
In a similar fashion, how can we get the child of the element? I tried the following and did not work
child_element = element.find_element_by_xpath('/')
child_element = element.find_element_by_xpath('//')
To get to the child of the WebElement you need to set the context to the current element using the dot character i.e. .. So effectively your line of code can be either of the following:
child_element = element.find_element_by_xpath('./')
or
child_element = element.find_element_by_xpath('.//')
Related
I'm trying to use relative locators in selenium 4, but I'm not having much luck with it.
I found an example here, but even though I'm able to find the first element, the second line doesn't work and it seems to be stuck there (I cannot close the browser automatically afterwards).
decision_div = browser.find_element(By.CLASS_NAME, "decisions")
conclusion_div = browser.find_element(locate_with(By.TAG_NAME, "div").below(decision_div))
How can I get it to find the next div right below the one with the specified class name?
As you are able to find the first element, I don't see any issues in your code as such:
decision_div = browser.find_element(By.CLASS_NAME, "decisions")
conclusion_div = browser.find_element(locate_with(By.TAG_NAME, "div").below(decision_div))
You just need to ensure that the the element with the value of class attribute as decisions is above the desired <div> element as follows:
<sometagname class="decisions" ...></div>
<div class="some class" ...></div>
Note : You have to add the following imports :
from selenium.webdriver.support.relative_locator import locate_with
References
You can find a couple of relevant detailed discussions in:
How to get the count of likes from a Twitter post using Selenium?
Selenium 4 relative locators are dealing with pair of web elements with the similar size and adjacent positions, not what you are trying to do here.
In this case the div element you are trying to locate is similarly nested below the parent element located by decisions class name.
So, you can simply locate the conclusion_div element with this code line:
conclusion_div = browser.find_element(By.XPATH, "//div[#class='decisions']//div")
But since the locator above gives 13 matches and I don't know which of them you want to locate it could be:
conclusion_div = browser.find_element(By.XPATH, "//div[#class='decisions']//div")
Or maybe
conclusion_div = browser.find_element(By.XPATH, "//*[#class='decisions']//div[contains(#class,'carousel')]")
Or maybe
conclusion_div = browser.find_element(By.XPATH, "//*[#class='decisions']//div[#class='decision-image']")
This is HTML code of that page
From there I want to access the 2nd element by using class name "maxbutton-1" as it has 3 same buttons and I can't use xpath or any constant selector so want to use the indexing with class and can't find anything to do that in python particular.
Also tried the method used in java to do same thing but it didn't worked.
Link of that same page
just trying to automate the movie downloading process for any movie.
Thank you.
To click on first, second or third button, try to change number of element:
el1 = driver.find_element_by_xpath("(//a[#class='maxbutton-1 maxbutton maxbutton-download-links'])[1]")
el2 = driver.find_element_by_xpath("(//a[#class='maxbutton-1 maxbutton maxbutton-download-links'])[2]")
el3 = driver.find_element_by_xpath("(//a[#class='maxbutton-1 maxbutton maxbutton-download-links'])[3]")
then you can extract element href/link attribute like that:
link = el.get_attribute('href')
or click it like that:
el.click()
I have a google form that I am webscraping(at least trying to). I want to look through it to find text where it says "Name ", then find the parent div of the whole block that contains that question and look for an input element where I can use send_keys() to fill out my name. I was able to find "Name " and find the parent div.
src = result.content
driver = webdriver.Chrome()
driver.get('https://exampleform.com')
soup = BeautifulSoup(src, 'html.parser')
name = soup.find(string="Name ")
nameBlock = name.find_parents('div', class_="freebirdFormviewerViewNumberedItemContainer", limit = 1)
if soup.find(string="Name "):
print('yes')
#prints yes
if name.find_parents('div', class_="freebirdFormviewerViewNumberedItemContainer", limit = 1):
print('okay')
#prints okay
if nameBlock.find('input'):
print('yup')
#gets error
# Also have tried nameBlock.find(tag = 'input')
# and nameBlock.find_element_by_tag_name('input)
# and name.find_parents('div', class_="freebirdFormviewerViewNumberedItemContainer", limit = 1).find('input)
I have tested out that I have found the parent function by printing out the variable "nameBlock" and was able to get the whole parent div and saw with the input tag there in the console. But then I get this error when I try the use the final "if" statement to see if I was able to locate the input element:
AttributeError: ResultSet object has no attribute 'find_elements_by_tag_name'. You're probably treating a list of elements like a single element. Did you call find_all() when you meant to call find()?
I think it has the parent selected as each child within that parent as well so every child is looking for
nameBlock.find('input')
but I am not really sure how I would go about just selecting the child input element. Any suggestions? Also here is the HTML to better help understand my issue.
AttributeError: ResultSet object has no attribute 'find_elements_by_tag_name'. You're probably treating a list of elements like a single element. Did you call find_all() when you meant to call find()?
The error says that You have used find_elements_by_tag_name() which returns as list not the webelement.
Change this to
find_element_by_tag_name() which will return as webelement and you can now use send_keys() method.
i want to get the second child element of content.When i try this code it says the nth-child(2) is not a valid expression. How can i get the child element of content?
content= stream.find_elements_by_class_name("content")
for l in content:
child = l.find_elements_by_xpath("nth-child(2)")
print(child.tag_name)
This solution works for me.
child = l.find_elements_by_xpath("./*[2]").
I try to index over results returned by an xpath. For example:
xpath = '//a[#id="someID"]'
can return a few results. I want to get a list of them. I thought that doing:
numOfResults = sel.get_xpath_count(xpath)
l = []
for i in range(1,numOfResults+1):
l.append(sel.get_text('(%s)[%d]'%(xpath, i)))
would work because doing something similar with firefox's Xpath checker works:
(//a[#id='someID'])[2]
returns the 2nd result.
Ideas why the behavior would be different and how to do such a thing with selenium
Thanks
Can you try the xpath /html/descendant::a[#id="someID"] You can replace the /html with something else that is an ancestor of your links like id('content'). You should then be able to locate individual links using [1], [2] etc.
From the XPath TR at http://www.w3.org/TR/xpath#path-abbrev:
NOTE: The location path //para[1] does not mean the same as the location path /descendant::para[1]. The latter selects the first descendant para element; the former selects all descendant para elements that are the first para children of their parents.
The answer is that you need to tell selenium that you're using xpath:
numOfResults = sel.get_xpath_count(xpath)
l = []
for i in range(1,numOfResults+1):
l.append(sel.get_text(xpath='(%s)[%d]'%(xpath, i)))
In Selenium you normally do it without the extra brackets so your loop would look like the following
numOfResults = sel.get_xpath_count(xpath)
l = []
for i in range(1,numOfResults+1):
l.append(sel.get_text('%s[%d]'%(xpath, i)))
And that will produce a valid XPath in Selenium like //a[#id='someID'][2]