Python Selenium - Constantly changing web element ID - python

I'm trying to use Selenium to find a web element that I know is the To field in a web email application (please see picture). I am able to successfully identify this web element and use send_keys to send an email address to this field.
However, the issue is the id always seems to cycle between 299 and 3 other numbers like 359 or 369.
Here's the code Im using. Is there another way I can account for this changing ID?
to_field = wait.until(EC.element_to_be_clickable((By.ID, "v299-to-input")))
print(to_field)
to_field.send_keys(email_reciever)
Thanks
PS- The web email application is fastmail.com

Since the ID attribute is changing, you have to build your locator on some other, stable parameter. The following CSS Selector is stable:
to_field = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".s-compose-to textarea")))
print(to_field)
to_field.send_keys(email_reciever)
The same can be done with the use of XPath locator:
to_field = wait.until(EC.element_to_be_clickable((By.XPATH, "//div[contains(#class,'s-compose-to')]//textarea")))
print(to_field)
to_field.send_keys(email_reciever)

You can use following css selector to identify the element.
to_field = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "textarea[id$='-to-input']")))
print(to_field)
to_field.send_keys(email_reciever)
This will identify the element id ends with the -to-input static value
to_field = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, "textarea.v-EmailInput-input")))
print(to_field)
to_field.send_keys(email_reciever)
This will identify the element with tagname.classname

Related

Having problem with the usage of driver find element by (Selenium)

I'am trying to make a bot that auto logins to a website.
In order to write the username I'm trying to use
driver.find_element_by_variable("username").send_keys(username)
When I'm looking that spesific variable from website on inspect the varible is two word like matinput formcontrolname.
On any other website if that varible is one word like id I simply write id after by_ and it works what can I do in this situation?
Selenium won't allow you to use:
find_element_by_variable()
but you have to use either of the predefined Locator Strategies as listed in the By implementation which are as follows:
CLASS_NAME= class name
driver.find_element(By.CLASS_NAME, "element_classname")
CSS_SELECTOR= css selector
driver.find_element(By.CSS_SELECTOR, "element_css_selector")
ID= id
driver.find_element(By.ID, "element_id")
LINK_TEXT= link text
driver.find_element(By.LINK_TEXT, "element_link_text")
NAME= name
driver.find_element(By.NAME, "element_name")
PARTIAL_LINK_TEXT= partial link text
driver.find_element(By.PARTIAL_LINK_TEXT, "element_partial_link_text")
TAG_NAME= tag name
driver.find_element(By.TAG_NAME, "element_tag_name")
XPATH= xpath
driver.find_element(By.XPATH, "element_xpath")

Selenium cant locate element inside ::before ::after

Element to be located
I am trying to locate a span element inside a webpage, I have tried by XPath but its raise timeout error, I want to locate title span element inside Facebook marketplace product. url
here is my code :
def title_detector():
title = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.XPATH, 'path'))).text
list_data = title.split("ISBN", 1)
Try this xpath //span[contains(text(),'isbn')]
You can't locate pseudo elements with XPath, only with CSS selector.
I see it's FaceBook with it's ugly class names...
I'm not sure this will work for you, maybe these class names are dynamic, but it worked for me this time.
Anyway, the css_locator for that span element is .dati1w0a.qt6c0cv9.hv4rvrfc.discj3wi .d2edcug0.hpfvmrgz.qv66sw1b.c1et5uql.lr9zc1uh.a8c37x1j.keod5gw0.nxhoafnm.aigsh9s9.qg6bub1s.fe6kdd0r.mau55g9w.c8b282yb.iv3no6db.o0t2es00.f530mmz5.hnhda86s.oo9gr5id
So, since we are trying to get it's before we can do it with the following JavaScript script:
span_locator = `.dati1w0a.qt6c0cv9.hv4rvrfc.discj3wi .d2edcug0.hpfvmrgz.qv66sw1b.c1et5uql.lr9zc1uh.a8c37x1j.keod5gw0.nxhoafnm.aigsh9s9.qg6bub1s.fe6kdd0r.mau55g9w.c8b282yb.iv3no6db.o0t2es00.f530mmz5.hnhda86s.oo9gr5id`
script = "return window.getComputedStyle(document.querySelector('{}'),':before').getPropertyValue('content')".format(span_locator)
print(driver.execute_script(script).strip())
In case the css selector above not working since the class names are dynamic there - try to locate that span with some stable css_locator, it is possible. Just have to try it several times until you see which class names are stable and which are not.
UPD:
You don't need to locate the pseudo elements there, will be enough to catch that span itself. So, it will be enough something like this:
span_locator = `.dati1w0a.qt6c0cv9.hv4rvrfc.discj3wi .d2edcug0.hpfvmrgz.qv66sw1b.c1et5uql.lr9zc1uh.a8c37x1j.keod5gw0.nxhoafnm.aigsh9s9.qg6bub1s.fe6kdd0r.mau55g9w.c8b282yb.iv3no6db.o0t2es00.f530mmz5.hnhda86s.oo9gr5id`
def title_detector():
title = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.CSS_SELECTOR, 'span_locator'))).text
title = title.strip()
list_data = title.split("ISBN", 1)

How to get div text by id with selenium

I am trying to get a book's description text from its amazon webpage. I get the book's image and title and price fine by using driver.find_element_by_id, but when it comes to the description which is in a div with id="iframeContent", it doesn't work. Why? I have also tried WebDriverWait but no luck.
I use the following code:
def get_product_description(self, url):
"""Returns the product description of the Amazon URL."""
self.driver.get(url)
try:
product_desc = self.driver.find_element_by_id("iframeContent")
except:
pass
if product_desc is None:
product_desc = "Not available"
return product_desc
Since that element is inside the iframe you have to switch to that iframe in order to access elements inside the iframe.
So first you have to locate the iframe
iframe = driver.find_element_by_id("bookDesc_iframe")
then switch to it with
driver.switch_to.frame(iframe)
Now you can access the element located by the div#iframeContent css_selector
And finally you should get out from the iframe to the default content with
driver.switch_to.default_content()
Credits to the author
you need to use text method from selenium.
try:
product_desc = self.driver.find_element_by_id("iframeContent").text
print(product_desc)
except:
pass
Update 1:
There's a iframe involved so you need to change the focus of webdriver to iframe first
iframe = self.driver.find_element_by_id("bookDesc_iframe")
self.driver.switch_to.frame(iframe)
product_desc = self.driver.find_element_by_id("iframeContent").text
print(product_desc)
Now you can access every element which is inside bookDesc_iframe iframe, but the elements which are outside this frame you need to set the webdriver focus to default first, something like this below :
self.driver.switch_to.default_content()

unable to find that exists and not an iframe using selenium

I'm making a project which goes to my orders page on amazon and collects data like product name, price, delivery date using selenium (cuz there is no api for that, and cant do with bs4). I get login and get to orders page without any problem.But I'm stuck where i have to find the delivery date using find element by class( I chose class because all other delivery date text have same class), but selenium says it cannot find it.
No, its not in an iframe as i cant see the option for This Frame when i right click on that element.
here is the code -
import requests
from selenium import webdriver
import time
userid = #userid
passwd = #passwd
browser = webdriver.Chrome()
browser.get('https://www.amazon.in/gp/your-account/order-history?ref_=ya_d_c_yo')
email_input = browser.find_element_by_id('ap_email')
email_input.send_keys(userid)
email_input.submit()
passwd_input = browser.find_element_by_id('ap_password')
passwd_input.send_keys(passwd)
passwd_input.submit()
time.sleep(5)
date = browser.find_element_by_class_name('a-color-secondary value')
print(date.text)
Finding element by xpath seems to work, but fails to find the date for all orders as xpath is different for every element.
Any help is appreciated.
Thanks
Refers to this line:
date = browser.find_element_by_class_name('a-color-secondary value')
It seem like your element target having multiple class name, a-color-secondary and value. Sadly .find_element_by_class_name just for single class name.
Instead you can use .find_element_by_css_selector:
date = browser.find_element_by_css_selector('.a-color-secondary.value')

How to click the icon using selenium

I am trying to automate my certain activities using selenium. I was launching a webpage and a security windows popup appears for the login credentials.
I have automated that using Autoit. Now after login I need to click on the option and I have tried it based on the find_element_by_text and find_element_by_id.
I was getting an error as Unable to find the element with CSS selector and I have seen some other post in the StackOverflow with the same issue but I could not able to fix it by myself.
Here is how my HTML looks like. Could you please guide me on this and also please share any document for further checking. Thanks.
driver = webdriver.Ie(r"C:\\IEDriverServer\\IEDriverServer.exe")
driver.get('URL of the page')
#driver.implicitly_wait(10) # seconds
autoit.win_wait("Windows Security")
# now make that crap active so we can do stuff to it
autoit.win_activate("Windows Security")
# type in the username
autoit.send('username')
# tab to the password field
autoit.send("{TAB}")
# type in the password
autoit.send('password')
# kill!
autoit.send("{ENTER}")
driver.maximize_window()
driver.implicitly_wait(120) # seconds
#submit_button_incidents = driver.find_element_by_link_text("3-Normal Incidents")
submit_button_incidents= driver.find_element_by_id("nodeImgs13pm")
submit_button_incidents.click()
driver.implicitly_wait(10)
++ updating the info
I have tried to copy the whole HTML but the page was restricted so I cant able to view the full HTML page other than the basic templates. Adding some more screenshots of the developer tools.
Here how my webpage looks like.
try with this code :
submit_button_incidents = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//span[contains(text(),'My Group'])")))
submit_button_incidents.click()
and do not use implicit wait too many times in code.
Implicit wait is set for life time of web driver instance.
Reference :
Selenium official document for wiats
Xpath tutorial
cssSelector tutorial
UPDATE :
As OP has shared the HTML code. As per the requirement you can go ahead with this code.
As there are two elements with text as My Groups's queue.
For first one you can write XPATH as :
//a[#class='scbdtext']/span[contains(text(),'My Group')]
Code:
submit_button_incidents = WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//a[#class='scbdtext']/span[contains(text(),'My Group')]")))
submit_button_incidents.click()
For second one you can write XPATH as :
//a[#class='scbdtextfoc']/span[contains(text(),'My Group')]
Code :
submit_button_incidents = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.XPATH, "//a[#class='scbdtextfoc']/span[contains(text(),'My Group')]")))
submit_button_incidents.click()
Hope this will help.
Use ActionChains with double click for this to work in Python.
from selenium.webdriver import ActionChains
# Get the element however you want
element = driver.find_element_by_xpath("//a[#class='scbdtextfoc']/span[contains(text(),'My Group')]")
ActionChains(driver).double_click(settings_icon).perform()

Categories

Resources