Selenium webdriver - element can be found but is not visible? - python

I am working on a personal project to make a python script to log in to a site and do few tasks for me, and I've decided to use the Selenium web driver. Currently I am stuck on the log in part.
driver = webdriver.Chrome()
driver.get("https://pucatrade.com")
puca_username = "example#username"
user_fieldID = "login"
user_fieldelement = driver.find_element_by_id(user_fieldID)
user_fieldelement.send_keys(puca_username)
However, it gives me selenium.common.exceptions.ElementNotVisibleException: Message: element not visible on the send_keys call. I know that find_element_by_id finds the element because I've tested with print user_fieldelement.get_attribute('id'), and it prints login. So if find_element_by_id works can find the element, how come send_keys can't?

There are multiple inputs having id="login". You are interested in the one located in the login form on the very right which is inside the div with id="home-login":
form = driver.find_element_by_id("home-login")
# login
user_fieldelement = form.find_element_by_id(user_fieldID)
user_fieldelement.send_keys(puca_username)
# password
passwd_fieldelement = form.find_element_by_id(passwd_fieldID)
user_fieldelement.send_keys(puca_password)

I'm still not sure why some websites has many fields with same name and id... but as I was only interested on the visible ones, I did this little function to get the right field.
def find_visible_element_by_name(name):
# Websites, for some reason, has many fields with the sama name and ID! This gets the first one that is visible.
# http://stackoverflow.com/questions/32462116/selenium-webdriver-element-can-be-found-but-is-not-visible
fields = self.sel.find_elements_by_name(name)
for f in fields:
if f.is_displayed():
return f
return None
self.sel is the Selenium driver object.

Related

How can I access the same website twice without losing the settings, using Selenium?

I access a website, login and then instead of going through the process of finding and writing into the website's search field, I thought I'd simply re-access the website through a URL with the search query I want.
The problem is that when I access the website with the second "driver.get" (last line of code in the code below), it's as though it forgets that I logged in previously; as though it was a totally new session that I opened.
I have this code structure:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.chrome.service import Service
path = Service("C://chromedriver.exe")
driver = webdriver.Chrome(service=path)
driver.get('https://testwebsite.com/')
login_email_button = driver.find_element(By.XPATH,'XXXXX')
login_email_button.click()
username = driver.find_element(By.ID, 'email')
password = driver.find_element(By.ID, 'password')
username.send_keys('myuser')
password.send_keys('mypassword')
driver.get('https://testwebsite.com/search?=televisions')
when you do
driver.get('https://testwebsite.com/search?=televisions')
you're opening new session with no cookie or data of previous session. You can try to duplicate tab instead, to keep you logged in. You can do with:
Driver.execute_script
url = driver.current_url
driver.execute_script(f"window.open('{url}');")
driver.switch_to.window(window_handles[1])
# if you want give a name to tab, pass it as second param like
driver.execute_script(f"window.open('{url}', 'second_tab_name');")
driver.switch_to.window('second_tab_name')
remember to use the switch if you want go back to the main tab

Python Selenium: Click Instagram next post button

I'm creating an Instagram bot but cannot figure out how to navigate to the next post.
Here is what I tried
#Attempt 1
next_button = driver.find_element_by_class_name('wpO6b ')
next_button.click()
#Attempt 2
_next = driver.find_element_by_class_name('coreSpriteRightPaginationArrow').click()
Neither of two worked and I get a NoSuchElementException or ElementClickInterceptedException . What corrections do I need to make here?
This is the button I'm trying to click(to get to the next post)
I have checked your class name coreSpriteRightPaginationArrow and i couldn't find any element with that exact class name. But I saw the class name partially. So it might help if you try with XPath contains as shown below.
//div[contains(#class,'coreSpriteRight')]
another xpath using class wpO6b. there are 10 elements with same class name so filtered using #aria-label='Next'
//button[#class='wpO6b ']//*[#aria-label='Next']
Try these and let me know if it works.
I have tried below code and it's clicking next button for 10 times
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
if __name__ == '__main__':
driver = webdriver.Chrome('/Users/yosuvaarulanthu/node_modules/chromedriver/lib/chromedriver/chromedriver') # Optional argument, if not specified will search path.
driver.maximize_window()
driver.implicitly_wait(15)
driver.get("https://www.instagram.com/instagram/");
time.sleep(2)
driver.find_element(By.XPATH,"//button[text()='Accept All']").click();
time.sleep(2)
#driver.find_element(By.XPATH,"//button[text()='Log in']").click();
driver.find_element(By.NAME,"username").send_keys('username')
driver.find_element(By.NAME,"password").send_keys('password')
driver.find_element(By.XPATH,"//div[text()='Log In']").click();
driver.find_element(By.XPATH,"//button[text()='Not now']").click();
driver.find_element(By.XPATH,"//button[text()='Not Now']").click();
#it open Instagram page and clicks 1st post and then it will click next post button for the specified range
driver.get("https://www.instagram.com/instagram/");
driver.find_element(By.XPATH,"//div[#class='v1Nh3 kIKUG _bz0w']").click();
for page in range(1,10):
driver.find_element(By.XPATH,"//button[#class='wpO6b ']//*[#aria-label='Next']" ).click();
time.sleep(2)
driver.quit()
As you can see, the next post right arrow button element locator is changing between the first post to other posts next page button.
In case of the first post you should use this locator:
//div[contains(#class,'coreSpriteRight')]
While for all the other posts you should use this locator
//a[contains(#class,'coreSpriteRight')]
The second element //a[contains(#class,'coreSpriteRight')] will also present on the first post page as well, however this element is not clickable there, it is enabled and can be clicked on non-first pages only.
As you can see on the picture below, the wp06b button is inside a lot of divs, in that case you might need to give Selenium that same path of divs to be able to access the button or give it a XPath.
It's not the most optimized but should work fine.
driver.find_element(By.XPATH("(.//*[normalize-space(text()) and normalize-space(.)='© 2022 Instagram from Meta'])[1]/following::*[name()='svg'][2]")).click()
Note that the XPath leads to a svg, so basically we are clicking on the svg element itself, not in the button.

Selenium can't find 99% of elements, why?

I'm using Selenium with Python and Firefox on Windows 7.
Running through my script, at some point Selenium can't find any elements beside and after I navigated to a certain part of a website.
The website belongs to an E-Mail provider called freemail (https://web.de/). I have set up a test account to complete a training project from chapter 11 of the book "Automate the Boring Stuff with Python".
Python, Selenium and Firefox are all up to date. And before this certain part of the website everything was working fine (including finding tags, class names, id's etc.).
I tried like 10 different ways to click one of the ways to navigate to the inbox of the E-Mail provider but had no luck in making it work.
Here is the HTMLcode with the highlighted element I want Selenium to click.
Here another image of the Website itself with the button highlighted in the upper left corner.
And this is the code for my script:
## This program navigates through the website of an
## e-mail provider and sends a mail automatically.
# Import necessary modules
from selenium import webdriver
# Mail account info
mailLink = 'https://web.de/'
mailAddress = 'testing2772#web.de' # This is just a test account
mailPw = 'ewaa11ewaa11'
# Recipient % content of the e-mail
recipient = 'pradicradr#matra.top'
mailContent = 'Test this awesome string.'
# Set up browser
browser = webdriver.Firefox()
browser.get(mailLink)
# Log into account
browser.find_element_by_class_name('icon-freemail').click()
browser.find_element_by_id('freemailLoginUsername').send_keys(mailAddress)
pwElem = browser.find_element_by_id('freemailLoginPassword')
pwElem.send_keys(mailPw)
pwElem.submit()
# Close notification overlay if it pops up
try:
browser.find_element_by_class_name('layerCloser').click()
except:
pass
## At this point Selenium can't Find 99% of elements including the one I need
## Testing if Selenium finds basic elements
testElem1 = browser.find_element_by_tag_name('html') # works
testElem2 = browser.find_element_by_tag_name('body') # works
testElem3 = browser.find_element_by_tag_name('div') # works
## Click link to inbox (all of these variants won't work somehow)
linkToInbox = browser.find_element_by_class_name('nx-track-sec-click-communication-newmail') # try by class_name
linkToInbox = browser.find_element_by_xpath("/html/body/div[3]/div/div[3]/div[1]/ul/li[3]/a") # try by XPath
linkToInbox = browser.find_element_by_link_text('E-Mail schreiben') # try by link_text
linkToInbox = browser.find_element_by_css_selector('a.nx-track-sec-click-communication-newmail') # try by CSS selector
linkToInbox = browser.find_element_by_css_selector('a.newmail') # try by CSS selector
linkToInbox = browser.find_element_by_css_selector('a.nx-track nx-track-sec-click-communication-newmail newmail') # another try by CSS selector
linkToInbox = browser.find_element_by_css_selector('a[title="E-Mail schreiben"]') # another try by CSS selector
## TODO: Click link to write a new mail
## TODO: Fill in recipient and mail content
## TODO: Send mail and close program
I guess it has something to do with an iframe? But I'm a beginner and I don't know how to handle this :/
Thanks in advance!
EDIT:
I solved the problem by finding another button that linked to the inbox with
browser.find_element_by_xpath("/html/body/atlas-app/atl-navbar/atl-actions-menu/div[1]/div[1]/atl-menu-item[2]/pos-icon-item/span/span").click(). This button is not within an iframe, so no problem here.
However, it is still strange that I can't enter any iframes. Here is another image to make it more clear. Does anybody know how to switch to that iframe?
browser.switch_to.default_content() and then browser.switch_to.frame('home') doesn't do the trick...
SECOND EDIT:
KunduK's answer did it.
The problem was, that the script needs to wait for the iframe to become available and then for the button to become available after that. See his post further down for the exact approach. Thanks everyone!
To click on the E-Mail schreiben link you need to switched to iframe first and then click on link.Use WebDriverWait and frame_to_be_available_and_switch_to_it and then use element_to_be_clickable
WebDriverWait(browser,20).until(EC.frame_to_be_available_and_switch_to_it((By.NAME,'home')))
WebDriverWait(browser,10).until(EC.element_to_be_clickable((By.XPATH,'//div[#id="navigation"]//ul//li[#class="item"]//a[#title="E-Mail schreiben"]'))).click()
You need to use following imports to execute above code.
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
I guess it has something to do with an iframe?
Since the elements you are trying to find are in an iframe, you must first switch to the iframe before finding the elements. Your iframe has a name=home attribute, so you should be able to add:
driver.switch_to.frame('home')
... then find the elements.
Once you are done interacting with the iframe and want to switch back to the top level content, use:
driver.switch_to.default_content()
Option 1
linkToInbox = browser.find_element_by_css_selector('a.nx-track.nx-track-sec-click-communication-newmail.newmail') # try by CSS selector
Option 2
use the title property of the anchor link
linkToInbox = browser.find_element_by_css_selector('a[title="E-Mail schreiben"]')
option 3
re-read the docs: https://selenium-python.readthedocs.io/locating-elements.html

sending message on youtube live chat with selenium using python

I was trying to make a script using python and selenium, to spam a massage on youtube live stream for a giveaway, i was able to do most of the task successfully until on line (33), where i was trying to locate the youtube live chat box by(.find_element_by_...?) it was showing all kind of error like,AttributeError: 'WebDriver' object has no attribute or failed to locate element_by_...? 'find_element_by_text,xpath,id.class, etc
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
email = ''
password = ''
gmail_link = 'http:\\www.gmail.com'
driver = webdriver.Firefox('D:\Projects\python projects')
driver.get(gmail_link)
time.sleep(4)
#email send_keys
driver.find_element_by_id('identifierId').send_keys(email)
#Email_next button xpath.click
driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[2]/div[2] /div/div/div[2]/div/div[2]/div/div[1]/div/content/span').click()
time.sleep(4)
#password xpath
driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[2]/div[2]/div/div/div[2]/div/div[1]/div/form/content/section/div/content/div[1]/div[1]/div/div/div/div/div[1]/div/div[1]/input').send_keys(password)
time.sleep(2)
#password button xpath.click
driver.find_element_by_xpath('/html/body/div[1]/div[1]/div[2]/div[2] /div/div/div[2]/div/div[2]/div/div[1]/div/content/span').click()
time.sleep(5)
#A random youtube live link
driver.get('https://www.youtube.com/watch?v=VTqTnbe6b1g')
time.sleep(5)
# youtube live chat box
driver.find_element_by_text('Say somthing...').send_keys('#PUBGMOBILE')
time.sleep(3)
# youtube live chat box button
driver.find_element_by_id('//*[#id="button"]').click()
Basically that div is associated with 'input' event so you have to dispatch the 'input' event once you enter the value in the div.
Here is the code which I was able to execute successfully form console (FYI this is JS you can use the same logic in your test and language).
ele = document.querySelector('div#input')
ele.textContent = 'test this sample data'
ele.dispatchEvent(new Event('input',{'bubles':true, 'cancelable':true}))
Line 1 is equals findelemnt by css
Line 2 enter the input
Line 3 fireevent 'input' on the element
WebElement chatEle = driver.find_element(By.CSS_SELECTOR('div#input')
chatEle.sendKeys "sample data"
driver.fireEvent(chatEle,"input")
should do the magic, couldn't test the code above as I don't have eclipse java environment on my machine. Test it and let us know.
Refer to Selenium FireEvent document for more information on the fireevent implementation.
Instead of looking for the element by its text you could use its xpath like you did before. I just looked at the chatbox for a YT livestream and the xpath seems to be called //*[#id="input"]
Edit:
Also, there could be something tricky where you need to click the element first before you can enter text.
don't use the [#id="input"] it was also given for another element too. You will not get the element. Use class name {yt-live-chat-text-input-field-renderer style-scope} this is unique you will get the element by this class name.
Your sending text to a wrong element
driver.find_element_by_text('Say somthing...').send_keys('#PUBGMOBILE')
This is lable not a textbox.

How to login into Openload.co using python selenium?

I am trying to login into openload.co using python Selenium Chrome Driver but I am getting the following error:
Message: element not interactable
I am using the following code and the error occurs in the last line of the code where I am not able to send the keys to the input tag.
from selenium import webdriver
path="path_to_chrome_driver" #add chromedriver path
driver=webdriver.Chrome(path)
from selenium.webdriver.common.keys import Keys
driver.get('https://openload.co/login')
email = driver.find_element_by_xpath('//*[#id="loginform-email"]')
email.send_keys("example#xyz.com")
I searched for the problem on stackoverflow and landed on the following link similar question which says that probably it is not pointing to correct xpath or css_selector. But I can't seem to find it.
What wrong am I doing here?
It's because there's a modal in the HTML made visible when you click the top right "Sign in" button. There's a duplication of ids. Could you try passing the password and username like this http://username:password#openload.co/ ?
#john try this, works for me:
driver.get('https://openload.co/login')
emails = driver.find_elements_by_xpath('//*[#id="loginform-email"]')
emails[1].send_keys("example#xyz.com")
Try to click on the element before sending keys.
driver.find_element_by_xpath('//*[#id="loginform-email"]').click()
Because of this the cursor will be active on the email textbox field so the element should interactivable.
There are two forms on page: first one for SignIn, second for LogIn. Both have input fields with the same #id values. You need to select form for LogIn:
email = driver.find_element_by_xpath('//h1[.="Login"]/following::*[#id="loginform-email"]')
email.send_keys("example#xyz.com")

Categories