How to switch to nested framesets using Python Selenium? - selenium

I need to reach a target frame with Xpath = html/frameset/frameset[1]/frame[2].
The HTML tree of the web site is as follows (the target frame is marked with a red *):
The web page is a chat room and I want to get the input box and the send button.
The following code logs into the chat room and tries to get to the target frame, but it fails there (Selenium hangs while trying to switch to that frame):
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome('/home/yky/Downloads/chromedriver')
driver.get('http://ip131.ek21.com/oaca_1/?ot=1')
### Log into chat room:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="mlogin"]/form/ul/li[1]/input'))).send_keys("UserOne")
driver.find_element_by_xpath('//*[#id="mlogin"]/form/div/span').click()
time.sleep(6)
### NONE of these works:
#driver.switch_to.frame(driver.find_element_by_css_selector("frame[name='ta']"))
#driver.switch_to.frame("ta")
#driver.switch_to_frame(driver.find_element_by_xpath('html/frameset/frameset[1]/frame[2]'))
#driver.switch_to.frame(2);
inputbox = driver.find_element_by_name("says_temp")
sendbutton = driver.findElement(By.xpath("//input[#value='送出']"));
I find the suggestion to ignore framesets to be very beguiling, as it doesn't make sense when the framesets contain other frames as a tree structure. Also, the problem is that the first frameset does not contain any frame; it just contains another frameset. So there is no way for Selenium to switch to the first frameset.
Please help!!

Related

How to click on an image (not button) using Selenium

Before this, I have automated a login into the website howe page. I was stuck trying to make it so that it clicks on the image to navigate to another webpage.
shop_button = driver.find_element(By.XPATH, "/html/body/footer/div/div[2]/a/img")
shop_button.click()
This is the code for the image hyperlink
You can use the below xpath
//p[text()='Shop']//preceding-sibling::img
this should locate the img node, however p tag which has Shop as a text has to be unique in nature.
If it's unique, you can click on it like:
Code trial 1:
time.sleep(5)
driver.find_element(By.XPATH, "//p[text()='Shop']//preceding-sibling::img").click()
Code trial 2:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//p[text()='Shop']//preceding-sibling::img"))).click()
Imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
PS: time.sleep(5) is just for visualization purpose, you should not use it ideally if code 2 works fine.
You want to redirect to another webpage by clicking on a image. According to the code snippet, I can see that Image tag is inside the tag, you can click on that.
Can you try this ?
shop_button = driver.find_element(By.XPATH,"/html/body/footer/div/div[2]/a")
shop_button.click()
Do let me know if this works.

How to click on SVG element in highcharts to download file using Selenium

My first question was related to this. In the meantime I have found a less efficient workaround. I'd still like automatically download these files.
I would like my script to click on the download icon, click on the Download XLS icon that follows of the page below. The green arrow is where I'd like to click.
The id of the highchart changes every time the page loads. I've tried to fix it it with code sample:
def unityengine_data():
driver.get("https://steamdb.info/tech/Engine/Unity/")
wait
WebDriverWait(driver,30).until(EC.visibility_of_element_located((By.XPATH, "div[contains(#id,'highcharts-')]//*[local-name() = 'svg']/*[name()='g'][6]/*[name()='g']/*[name()='image']"))).click
WebDriverWait(driver, 30).until(EC.visibility_of_element_located((By.XPATH, "div[contains(#id,'highcharts-')]//**[local-name() = 'div']/*[name()='ul'][6]/*[name()='li'][2]"))).click
os.rename("downloaded file path", "new file path")
return "Unity Engine apps data successfully downloaded"
Website image
Website after first click
I hope you can help.
You are simply missing // here at this line
WebDriverWait(driver,30).until(EC.visibility_of_element_located((By.XPATH, "div[contains(#id,'highcharts-')]//*[local-name() = 'svg']/*[name()='g'][6]/*[name()='g']/*[name()='image']"))).click
also, you should ideally create object of WebDriverWait once and reuse it whenever you want.
See the below code, I have improved one locator as well.
Code:
driver.maximize_window()
wait = WebDriverWait(driver, 30)
driver.get("https://steamdb.info/tech/Engine/Unity/")
wait.until(EC.visibility_of_element_located((By.XPATH, "//div[contains(#id,'highcharts-')]//*[local-name() = 'svg']/*[name()='g'][6]/*[name()='g']/*[name()='image']"))).click()
wait.until(EC.visibility_of_element_located((By.XPATH, "//li[text()='Download XLS']"))).click()
Imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
You were almost there. You just need three minor adjustments and one optimization as follows:
You need to add the leading // for an effective xpath.
click is a method so you need to click()
The xpath for the highchart image can be optimized a bit.
The element with text Download XLS is within local-name space, hence you don't need [local-name() = 'div']
Your effective code block will be:
driver.get("https://steamdb.info/tech/Engine/Unity/")
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#id,'highcharts-')]//*[local-name() = 'svg']//*[name()='g']//*[name()='image']"))).click()
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//ul[#class='highcharts-menu']//li[text()='Download XLS']"))).click()
Browser Snapshot;
References
You can find a couple of relevant detailed discussions in:
How to click on SVG elements using XPath and Selenium WebDriver through Java

How to use selenium and Python to click 'accept cookies' button in popup, how can I move on when popup has no x

I am new to using the selenium module. I have started with some simple tutorials which go ok until I get a popup.
Because the popup does not have an x, I am not able to apply other advice I have found online.
How to close pop up window in Selenium
However I have tried to inspect the code of the popup window and I can see that maybe I have a couple of options, close by referencing the link text 'Accept Cookies', or close by the button id which is "onetrust-accept-btn-handler"
This is the code I have so far.
import selenium
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
PATH = "C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://www.reed.co.uk/jobs/senior-insight-analyst/42347955")
driver.implicitly_wait(10)
link = driver.find_element_by_link_text("onetrust-accept-btn-handler")
link.click()
Trying
link = driver.find_element_by_link_text("onetrust-accept-btn-handler")
and
link = driver.find_element_by_link_text("Accept cookies")
Result in errors
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"link text","selector":"onetrust-accept-btn-handler"}
or
NoSuchElementException: Message: no such element: Unable to locate element: {"method":"link text","selector":"Accept cookies"}
I am wondering if there is any better command than link text if the button id is known, or am I missing another step in the process because it is a pop up? Any help appreciated. Thank you.
Please use the explicit wait so that your popup window can come up and your selenium script can detect the element and click on it.
Use the below code -
WebDriverWait(driver, 15).until(EC.element_to_be_clickable((By.ID, 'onetrust-accept-btn-handler'))).click()
Mark it as answer if it resolves your problem.
Thank you Swaroop Humane and Dev for your answers. The answer above works, I also needed to add in three more lines of import code before the solution managed to click the Accept cookies button in the pop up. https://selenium-python.readthedocs.io/waits.html
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
Final code below.
import selenium
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import time
PATH = "C:\Program Files (x86)\chromedriver.exe"
driver = webdriver.Chrome(PATH)
driver.get("https://www.reed.co.uk/jobs/senior-insight-analyst/42347955")
#driver.implicitly_wait(10)
#link = driver.find_element_by_link_text("onetrust-accept-btn-handler")
#link.click()
WebDriverWait(driver, 15).until(EC.element_to_be_clickable((By.ID, 'onetrust-accept-btn-handler'))).click()
Then this happened.
I probably need to figure out a way to run selenium while I am signed into this webservice, rather than let it run a new browser every time. Any ideas?

Element not Interactable when using the selenium function find element by name but works when using find element by xpath method

I have webpage where I am trying to login to it. When I use find element by name method to find the elements I get element not interactable error but when i use find element by xpath it works fine and no error. Can anyone explain me why it is not able to interact with element when found by name method?
Same issue is observed for User ID, Password and Login elements.
I am sure even when using by name method website is loaded and is ready for use.
Below is the screenshot of the Webpage login
My HTML code is as below
Below is the code am using
import xlrd
import openpyxl
import requests
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
from selenium.webdriver.support.ui import Select
from selenium.webdriver.chrome.options import Options
from selenium.webdriver import ChromeOptions, Chrome
opts = webdriver.ChromeOptions()
opts.add_experimental_option("detach", True)
def login_to_Portal(mBrowser):
mBrowser.find_element_by_id("userNameTrucks")
mBrowser.find_element_by_id("userNameTrucks").clear()
mBrowser.find_element_by_id("userNameTrucks").send_keys("xxxxx")
mBrowser.find_element_by_xpath("/html/body/div/router-view/section/div[2]/ul/li[4]/input")
#mBrowser.find_element_by_name("password").clear()
mBrowser.find_element_by_xpath("/html/body/div/router-view/section/div[2]/ul/li[4]/input").send_keys("xxxxx")
mBrowser.find_element_by_xpath("/html/body/div/router-view/section/div[2]/ul/li[5]/button").click()
#mBrowser.find_element_by_class_name("au-target").click()
#mBrowser.find_element_by_name("target")
#mBrowser.find_element_by_name("target").click()
mBrowser = webdriver.Chrome(executable_path = r'C:\chromedriver_win32\chromedriver.exe', options = opts )
mBrowser.get("https://grouptrucksportal.volvo.com/gpp/index.html")
time.sleep(10)
mBrowser.find_element_by_xpath("/html/body/div/compose[1]/section/div[1]/map/area[1]")
mBrowser.find_element_by_xpath("/html/body/div/compose[1]/section/div[1]/map/area[1]").click()
time.sleep(3)
mBrowser.find_element_by_xpath("/html/body/div/compose[3]/section/div[2]/div/ul/li[4]/a")
mBrowser.find_element_by_xpath("/html/body/div/compose[3]/section/div[2]/div/ul/li[4]/a").click()
time.sleep(5)
login_to_Portal(mBrowser)
Now am using xpatha and everything works fine.
When i use find element by name it fails with not interactable error
This error message...
ElementNotInteractableException: Message: element not interactable
...implies that the WebElement with whom you are trying to interact isn't interactable (isn't in interactable state) at that moment.
The two(2) main reasons for this error are:
Either you are trying to interact with a wrong/mistaken element.
Or you are invoking click() too early even before the element turns clickable / interactable.
Analysis and Solution
There are a couple of things you need to take care. In case of websites like Truck Dealer Online once you navigate to the Login page instead of find_element_by_id() or find_element_by_name() you have to induce WebDriverWait for the element_to_be_clickable().
As an example, to send a character sequence to the user name field you can use either of the following Locator Strategies:
Using ID:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.ID, "userNameTrucks"))).send_keys("SrinivasVenkataram")
Using CSS_SELECTOR:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.CSS_SELECTOR, "input#userNameTrucks"))).send_keys("SrinivasVenkataram")
Using XPATH:
WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[#id='userNameTrucks']"))).send_keys("SrinivasVenkataram")
Note : You have to add the following imports:
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
References
You can find a detailed discussion on ElementNotInteractableException in:
ElementNotInteractableException: Message: element not interactable error sending text in search field using Selenium Python

Can't find correct xpath for retweet or like button with selenium for chromedriver and python

I can't find the correct xpath to use for retweet and like on this page: https://twitter.com/snowfulls/status/1198269659465818115
Also, I need help finding the xpath for the second retweet button that comes up to confirm the retweet.
Is there a way to find xpaths automatically?
To answer your first question -- no, there is not a way to find XPaths automatically unless you use some kind of scanner tool. These XPaths are not always accurate though. The best approach is to use an XPath browser extension helper that will allow you to test out XPath expressions on a page in real-time. That is what I have used to help develop my solution.
To click the "Like" button on a tweet, you can use the following code:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# ensure the above references are added to use WebDriverWait correctly
# wait for the element to exist
like_button = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div[#aria-label='Like']")))
# click the like button
like_button.click()
To click the retweet button, similarly:
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
# ensure the above references are added to use WebDriverWait correctly
# wait for the element to exist
retweet_button = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div[#aria-label='Retweet']")))
# click the retweet button
retweet_button.click()
# now, confirm the retweet:
retweet_confirm = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, "//div[#data-testid='retweetConfirm']")))
# click the retweet confirm button
retweet_confirm.click()
The above solution uses a few simple extensions of Selenium library -- mainly, WebDriverWait and ExpectedConditions class. WebDriverWait allows us to wait up to a specified time for a condition to occur. This goes hand-in-hand with ExpectedConditions class, which measures the status of elements on the page to confirm whether or not a WebElement meets a certain condition.
So, WebDriverWait(driver, 10).until(EC.presence_of_element_located means "Wait up to 10 seconds for the presence of a WebElement" -- this WebElement then gets specified in the locator strategy, By.XPath, "....".
Hope this explanation helps a bit.