Let's say I want to scroll a scrollbar in some element.
As an example, let's take the link "https://www.w3schools.com/howto/howto_css_table_responsive.asp". If I run:
element = driver.find_element_by_xpath("//table")
I get the table element. But now, I want to scroll the scrollbar horizontally, that is controling the view of this table. How can I do this?
I already tried something like:
driver.execute_script("arguments[0].scrollLeft = 200;",element)
But I wasn't successfull. I also tried sending keys, but it didn't work too.
You do not need to actually be able to see elements for Selenium to target them.
Just proceed to target the elements that are 'off screen' as you would if they were on screen.
Selenium is targeting the DOM - which as a loose analogy which I will probably be roasted for in the comments is like a screen with infinite length and width - so no scrolling necessary - it (selenium) can already "see" everything 'on' that 'infinite screen'
If you are having trouble selecting specific elements from within the table in question (if you need a specific code snippet) please feel free to comment - I am rather familiar with Selenium.
EDIT:
In your specific case, since they are being loaded dynamically you are 100% correct that you will need to scroll to get the data. Let's take care of vertical scrolling by hitting the More Financial Data button at the bottom that expands the list.
Now for scrolling to the right - since we can just scroll all the way to the right and have all data that we need to access visible (assuming you don't have a Premium account).
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
driver = webdriver.Firefox()
url = "https://www.morningstar.com/stocks/xnas/tsla/financials"
driver.get(url)
driver.maximize_window()
# Click on Income Statement
xpath = '//*[#id="__layout"]/div/div[2]/div[3]/main/div[2]/div/div/div[1]/sal-components/section/div/div/div/div/div[2]/div/div/div[2]/div[2]/div/div[2]/div/div[2]/div[2]/div[1]/div[1]/a'
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath))).click()
# click on More Financials Detail Data
xpath = '//*[#id="__layout"]/div/div[2]/div[3]/main/div[2]/div/div/div[1]/sal-components/section/div/div/div/div/div[2]/div/div[2]/div/div[2]/div/div[3]/div[2]/div/a'
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, xpath))).click()
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
xpath='/html/body/div[2]/div/div/div[2]/div[3]/main/div[2]/div/div/div[1]/sal-components/section/div/div/div/div/div[2]/div/div[2]/div/div[2]/div/div[2]/div[4]/div/div[3]/div[2]/div[2]'
horizontal_bar_width = driver.find_element_by_xpath(xpath).rect['width']
slider = driver.find_element_by_xpath(xpath)
ActionChains(driver).click_and_hold(slider).move_by_offset(horizontal_bar_width/2, 0).release().perform()
Related
I am trying to select a button using selenium however i believe i am doing something wrong while writing my xpath can anyone please help me on this i need to select the currency Euro.
link :- https://www.booking.com/
Locator which i want to select
Locator which i have written
USD = self.find_element_by_xpath(f"//a[contains(text(),'selected_currency='Euro']")
USD.click()
The below xpath
//a[contains(#href,'EUR') and starts-with(#class,'bui-list')]
is present two times in HTML DOM.
Steps to check:
Press F12 in Chrome -> go to element section -> do a CTRL + F -> then paste the xpath and see, if your desired element is getting highlighted with 1/1 matching node.
In case you would like to select the first one which is in Suggest for you, there is no need to do anything with respect to XPath.
#pmadhu answer is misleading, since why would anyone look for first index in XPath when using with Selenium ? If there are multiple matching node, Selenium is always going to pick up the first element, So it really does not make any sense to me that why would someone use [1]
Nevertheless,
to click on Suggest for you EURO :
try:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//a[contains(#href,'EUR') and starts-with(#class,'bui-list')]"))).click()
except:
pass
Imports :
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
In case you are looking to click on second matching node for EUR,
in that case it make sense to use index 2.
XPath would look something like this :
(//a[contains(#href,'EUR') and starts-with(#class,'bui-list')])[2]
The text you are looking for: selected_currency='EUR' is in the data-modal-header-async-url-param parameter of the a tag. You should run the contains on that.
Edit:
Locator: //a[contains(#data-modal-header-async-url-param, 'selected_currency=EUR')]
As already explained, selected_currency=EUR is in the attribute - data-modal-header-async-url-param.
However you can select the required option, with below code.
The xpath for the EUR option can be - //div[contains(text(),'EUR')]. Since it highlights 2 elements in the DOM using this xpath- (//div[contains(text(),'EUR')])[1]. Its important to find unique locators. Link to refer
# Imports required for Explicit wait
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver.get("https://www.booking.com/")
wait = WebDriverWait(driver,30)
# Click on Choose currency option
wait.until(EC.element_to_be_clickable((By.XPATH,"//span[#class='bui-button__text']/span[contains(text(),'INR')]"))).click()
# Click on the EUR option.
euro_option = wait.until(EC.element_to_be_clickable((By.XPATH,"(//div[contains(text(),'EUR')])[1]")))
euro_option.click()
I am trying to extract data from this page using Python Selenium. The table is rendered by Tableau. I would need to input some data and then use the download button.
Interestingly, I can't access the elements inside the table from Selenium. I tried looking by id, class or xpath. I keep getting the NoSuchElementException. However, these elements are rendered in HTML and I can see them with the inspect tool. Does anyone know why this is, and how I can make them visible to Selenium?
EDIT1: It's not a problem of loading time. I tried with time.sleep() and I am also interacting directly with the page.
I can see your tables are inside iFrame. First go inside and then try to scrape table data.
WebDriverWait(driver, 20).until(EC.frame_to_be_available_and_switch_to_it((By.XPATH, "//iframe[contains(#src,'zika_Weekly_Agg_tben')]")))
# COde here to scrape data
driver.switch_to.default_content() # To come out of frame
You need to Import
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
This was quite challenging since it has 2 iframe followed by shadow element. And does not stop here. When you switch to the iframe you don't have iframe reference available to access the shadow element. you Can refer below code. It manage to get the tableau chart heading.
# Get first iframe and switch to it
root1 = driver.find_element_by_xpath("//div[#itemprop='articleBody']//iframe")
driver.switch_to.frame(root1)
# Grab the shadow element
shadow = driver.execute_script('return document')
# Get the iframe inside shadow element of first iframe
iframe2 = shadow.find_element_by_xpath("//body/iframe")
# switch to 2nd iframe
driver.switch_to.frame(iframe2)
print("selected 2nd iframe")
shadow_doc2 = driver.execute_script('return document')
print("second iframe")
heading = shadow_doc2.find_element_by_xpath("//div[#class='tab-textRegion-content']/span//span[text()='Cases of Zika Virus Disease']/ancestor::div[2]").text
print(heading)
Output -
I am writing a python script which will call a webpage and will select an option from the drop down to download that file. To do this task, I am using chropath. It is a browser extension which can give you the relative xpath or id for any button or field on the webpage and using that we can call it from python selenium script.
Above image shows the drop down menu in which I have to select 2019 as year and the download the file. In the lower part of the image, you can see that I have used chropath to get the relative xpath of the drop down menu which is //select[#id='rain']
Below is the code I am using:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Firefox()
driver.get("<URL>")
driver.maximize_window()
grbf = driver.find_element_by_xpath("//select[#id='rain']")
grbf.send_keys('2019')
grbf_btn = (By.XPATH, "//form[1]//input[1]")
WebDriverWait(driver, 20).until(EC.element_to_be_clickable(grbf_btn)).click()
from the above code, you can see that I am using xpath to select the drop down grbf = driver.find_element_by_xpath("//select[#id='rain']") and then sending keys as 2019 i.e. grbf.send_keys('2019') and after that I am calling download button to download it. But for some reason, its always selecting year 1999 from the drop down. I am not able to understand what is wrong in this. Is this correct approach to solve this. Please help. Thanks
I had the same problem time ago. Try this:
from selenium.webdriver.support.ui import Select
grbf = Select(driver.find_element_by_xpath("//select[#id='rain']"))
grbf.select_by_value('2019')
In the select_by_value() you have to use the value of the element in the dropdown.
By the way, if an element has id, use it.
grbf = Select(driver.find_element_by_id('rain'))
Try below code:
select = Select(driver.find_element_by_xpath("//select[#id='rain']"))
select.select_by_visible_text('2019')
Another approches to deal with dropdown:
Using Index of Dropdown :
select.select_by_index(Paass index)
Using valueof Dropdown :
select.select_by_value('value of element')
Using visible text of Dropdown :
select.select_by_visible_text('element_text')
In my opinion, I don't think this is the correct approach. You try to select the option which is dropdown (not a text box like ), so send key command does not work.
What you need to do is try to inspect HTML changing when clicking the dropdown and try to XPath for an option that you want to select.
If you still stuck at this problem, I recommend using katalon recorder which is a chrome extension to allow you to record and do UI testing
I am trying to write a simple program to open up chrome, go to Google, and click on "I'm Feeling Lucky." I see that it acts as if the cursor is placed over the icon, but it will not perform a click.
driver.get("https://www.google.com")
element = WebDriverWait(driver, 20) \
.until(EC.visibility_of_element_located((By.ID, "gbqfbb")))
element.click()
No errors occur in the code, but it will not click the element.
I cannot find that ID either.
here's what worked for me using css_selector
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from appium.webdriver.common.mobileby import, By
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("https://www.google.com")
element = WebDriverWait(driver, 20) \
.until(EC.visibility_of_any_elements_located((By. CSS_SELECTOR, '[name="btnI"][type="submit"]')))[0]
element.click()
I suggest to use visibility_of_any_elements_located over visibility_of_element_located. The reason is that the selector finds two elements. One visible and one that is not.
When using visibility_of_element_located it will use find_element and it will get the element that is not visible.
When using visibility_of_any_elements_located it will use find_elements and it will get both elements. it will loop through all elements and if one or more are visible it will return it right away.
Where you get that ID? When I visit the site, I don't see an element with that ID. It's possible that Google has some sort of way of manipulating this to make it harder for people to automate this process. It's possible that Google doesn't want you doing this.
Either way, you should be able to select the element by something else:
driver.get("https://www.google.com")
element = WebDriverWait(driver, 20) \
.until(EC.visibility_of_element_located((By. CSS_SELECTOR, '[jsaction="sf.lck"]')))
element.click()
driver.findElement(By.xpath("//div[#class='FPdoLc lJ9FBc']//following::input[#class='RNmpXc']")).click();
I'm playing around with a mini-challenge that's been set to automate a form response on survey monkey, I've set up a dummy survey for the purpose of this example.
Essentially, selenium is unable to click the box due to an error with a button display obscuring it.
ElementClickInterceptedException: Message: Element input id="234136539_1601280849" class="checkbox-button-input " name="234136539[]" type="checkbox"> is not clickable at point (237.5,345.5) because another element span class="checkbox-button-display "> obscures it
I've looked at this question which is Java specific, and I can't quite get my head around how I go about getting past this, I've tried implicit waits, clicking on the box around it but a little lost where to begin without learning Java.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get('https://www.surveymonkey.com/r/L9DJGXR')
vote_check = driver.find_element_by_id('234136539_1601280849')
vote_check.click()
This code should replicate the problem with the dummy survey.
Right-click on the checkbox next to "Me" and choose Inspect... what element is selected? The SPAN. That's because the SPAN overlaps the INPUT you want to click. That's what that error is telling you. You are trying to click on an element that is covered by another element. Selenium can't "see" the page to see that the element underneath is not really obscured.
The solution is to click either the SPAN that was in the error or the LABEL. It doesn't really matter which you do, both will work. Two CSS selectors are below
[id='234136539_1601280849'] + label // clicks the LABEL
^ has this ID
^ '+' means sibling
^ LABEL tag
[id='234136539_1601280849'] + label > span // clicks the SPAN
everything is the same as above until...
^ '>' means child
^ SPAN tag
To click the second check box associated with text Me you have to induce WebDriverWait for the element to be clickable and you can use the following solution:
Code Block:
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Firefox(executable_path=r'C:\Utility\BrowserDrivers\geckodriver.exe')
driver.get('https://www.surveymonkey.com/r/L9DJGXR')
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[#class='question-body clearfix notranslate ']//following::label[2]"))).click()
Browser Snapshot: