Script can't find Element but Console can [Selenium] [Python] - python

I'm trying to write script to automate the process of downloading the instagram stories but I'm failing already when trying to log in.
I'm writing the code inside Pycharm. I just tried my usual approach to any problem. First, solve it with typing the commands out in the console and if it works writing the commands which worked inside the console down in a script. But here is the issue. The function which worked perfectly fine inside the python console fails inside the script.
I've noticed that my selenium was outdated but upgrading it didn't help ether. I also made a new project to test weather that made difference, which it didn't.
I've also tried skipping the first step inside the script and just opening the url to which I'm redirected. But the second commands failed as well.
When I create a new variable to store the output of the driver.find_element_by_link_text() in, it returns an empty list. This leads me to belive that somehow selenium is unable to search the contetns of the page.
I've also tried the same on Chrome and Safari. This also didn't work.
Here is the code:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get("https://instagram.com/")
#next command fails
driver.find_element_by_link_text("Melde dich an.").click()
#if the first command is skipped by entering in the url
#in driver.get(https://www.instagram.com/accounts/login/?source=auth_switcher)
#the following command fails as well.
driver.find_element_by_name("username").send_keys("HereIsTheUsername")
driver.find_element_by_name("password").send_keys("HereIsThePassword")
driver.find_element_by_name("password").send_keys(Keys.RETURN)
driver.close()
In the console these commands worked as mentioned,
Here is what I've entered into the console:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
driver = webdriver.Firefox()
driver.get("https://instagram.com/")
driver.find_element_by_link_text("Melde dich an.").click()
#if it failed here would be an error message
element = driver.find_element_by_name("username")
With the script the error message is this:
Traceback (most recent call last): File
"/Users/alisot2000/PycharmProjects/Instagram downloader/venv/Main.py",
line 6, in
driver.find_element_by_link_text("Melde dich an.").click() File "/Users/alisot2000/PycharmProjects/Instagram
downloader/venv/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py",
line 428, in find_element_by_link_text
return self.find_element(by=By.LINK_TEXT, value=link_text) File "/Users/alisot2000/PycharmProjects/Instagram
downloader/venv/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py",
line 978, in find_element
'value': value})['value'] File "/Users/alisot2000/PycharmProjects/Instagram
downloader/venv/lib/python3.7/site-packages/selenium/webdriver/remote/webdriver.py",
line 321, in execute
self.error_handler.check_response(response) File "/Users/alisot2000/PycharmProjects/Instagram
downloader/venv/lib/python3.7/site-packages/selenium/webdriver/remote/errorhandler.py",
line 242, in check_response
raise exception_class(message, screen, stacktrace) selenium.common.exceptions.NoSuchElementException: Message: Unable to
locate element: Melde dich an.

Issues you might be experiencing:
1. Synchronization Issue
For most automation tasks, there will be different loading times of web pages based on the processing power of the machine and how strong your internet connection is.
To solve this there are library import Waits from selenium that we can use.
Here is a sample below:
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.Firefox()
driver.get("http://somedomain/url_that_delays_loading")
try:
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located((By.ID, "myDynamicElement"))
)
finally:
driver.quit()
2. Wrong language set in selenium profile
Selenium will use your locale in most cases when running automation scripts but in the case that you might want another language here is a sample code for FireFox.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
profile = webdriver.FirefoxProfile()
# switch out 'de' with another two character language code
profile.set_preference("intl.accept_languages",'de')
driver = webdriver.Firefox(firefox_profile=profile, executable_path='<insert_your_gecko_driver_path_here>')
driver.get("https://instagram.com/")
driver.close()
3. Working Code(Tested on Mojave 10.14.5)
Here is a diff of your code and the altered code: https://www.diffchecker.com/G0WWB4Ry
setup a virtualenv
pip install selenium
download geckodriver
set path to gecko driver in code
run script with success result
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
# these two imports are for setting up firefox driver and options
from selenium.webdriver.firefox.firefox_profile import FirefoxProfile
from selenium.webdriver.firefox.firefox_binary import FirefoxBinary
# import these three lines below if you are having synchronization issues
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
profile = webdriver.FirefoxProfile()
# here is where you need to set your language explicitly if its defaulting to an undesired language
# just replace the second parameter with your 2 character language code
# this line is not needed if your desired language is locale
profile.set_preference("intl.accept_languages",'de')
# throw in your path here <insert_your_gecko_driver_path_here>
driver = webdriver.Firefox(firefox_profile=profile, executable_path='<insert_your_gecko_driver_path_here>')
driver.get("https://instagram.com/")
# added these two lines below to solve synchronization issue
# element wasnt clickable until page finished loading
wait = WebDriverWait(driver, 10)
element = wait.until(EC.element_to_be_clickable((By.LINK_TEXT, "Melde dich an.")))
#next command fails
driver.find_element_by_link_text("Melde dich an.").click()
#if the first command is skipped by entering in the url
#in driver.get(https://www.instagram.com/accounts/login/?source=auth_switcher)
#the following command fails as well.
driver.find_element_by_name("username").send_keys("HereIsTheUsername")
driver.find_element_by_name("password").send_keys("HereIsThePassword")
driver.find_element_by_name("password").send_keys(Keys.RETURN)
driver.close()

def ClickElementByName(name,driver):
while True:
try:
driver.find_element_by_name(name).click()
break
except:
sleep(1)
pass
Too long to wait the website run.
Replace ClickElementByName("username", driver)

driver.find_element_by_xpath('//input[#name="username"]').send_keys("HereIsTheUsername")
driver.find_element_by_xpath('//input[#name="password"]').send_keys("HereIsTheUsername")
driver.find_element_by_xpath('//div[text()="Log In"]').click()

Related

Python Selenium Not Able to Grab XPATH

Recently the login for this site changed and no longer recognizes my Python bot. Specifically, the issue appears to be occurring on the login page where it is unable to select the username input textbox. The id for it is 'loginId' and the correct XPATH appears to be "//*[#name='loginId']"
The line I am attempting to use (that used to work) is:
WebDriverWait(driver, 10).until(EC.element_to_be_clickable((By.XPATH, "//*[#name='loginId']"))).send_keys(username)
The error message I am receiving clearly states it is not finding the element and is timing out:
File "C:\Users\Matt\Python3.9\lib\site-packages\selenium\webdriver\support\wait.py", line 80, in until
raise TimeoutException(message, screen, stacktrace)
selenium.common.exceptions.TimeoutException: Message:
I have tried all of the suggested names/paths/ids found in both Katalon Recorder and Selenium IDE. This does not appear to be an iFrame. Not sure what is going on.
Any thoughts or input would be helpful here. Link is provided up above if you can check it out that would be helpful. Thank you in advance!
Supplemental code [EDIT 07/05/2022]:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.chrome.options import Options
options = webdriver.ChromeOptions()
driver = webdriver.Chrome('C:\\Users\\Matt\\Documents\\Splitt\\Chromedriver\\chromedriver.exe', options=options)
driver.get("https://www.stellarmls.com/")
driver.maximize_window()
WebDriverWait(driver, 6).until(EC.element_to_be_clickable((By.XPATH, '//*[#id="login-form-row"]/form/div/div[3]/div/a'))).click()
driver.find_element(By.ID, "loginId").send_keys('username')
I didn't use your code and instead plugged in your site to a Selenium script I had and it worked without issue:
driver.find_element(By.NAME, "loginId").send_keys(username)
It essentially does the same thing without the explicit wait. The fact that it was missing didn't seem to be a problem.

Why is the Selenium output different if run interactively vs in a Python script?

I am using Selenium in Python 3 to get the page source of a site that uses JavaScript. When I run it interactively in an iPython shell, it works as I expect it to. However, when the exact same script is executed non-interactively, the page source is not fully rendered (the JavaScript components aren't rendered). What could be the reason for this? I am running the exact same code on the exact same machine (a headless Linux server).
#!/usr/bin/python3
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.chrome.options import Options
WINDOW_SIZE = "1920,1080"
chrome_options = Options()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--window-size={0}".format(WINDOW_SIZE))
chrome_options.add_argument("--no-sandbox")
service = Service('/usr/local/bin/chromedriver')
driver = webdriver.Chrome(service=service, options=chrome_options)
driver.get("https://www.stakingrewards.com/staking/?page=1&sort=rank_ASC")
src = driver.page_source
# Check page source length
print(len(src))
# Quit all windows related to the driver instance
driver.quit()
The output from the iPython shell is 220101, which is expected, while the output from the command line executed script ($ python script.py) is 38265. Thus, I am not effectively rendering the JavaScript components when I invoke the script from the command line. Why?!
The problem is not with running it interactively or as a script.
In your code, you're not really giving any time for the driver to render all the elements, resulting in incomplete source code. It just happened to be that running it interactively was a little bit faster than running it as a script, resulting in larger page source length. However, I was able to get much larger page source length using Waits(around 650k).
Waits can be used to wait for required elements to be visible/present etc. In your case I'm assuming it's the main table.
The given code below waits for the table to be visible and then returns the page source.
Code snippet-
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.common.exceptions import TimeoutException
driver.get("https://www.stakingrewards.com/staking/?page=1&sort=rank_ASC")
try:
#waiting for table data to be visible
delay=20 #20 second delay
WebDriverWait(driver, delay).until(EC.visibility_of_element_located((By.CLASS_NAME, 'rt-tbody')))
print(len(driver.page_source))
#raises Exception if element is not visible within delay duration
except TimeoutException:
print("Timeout!!!")
driver.quit()

How can I make the selenium chromedriver make wait until it maximizes the window?

I've been messing around with python/selenium a bit, now I got to use the "try" method. I want the driver to wait until it maximized the window, and then go on with the code. At the beginning it just went on executing all scripts and the chrome window got maximized whilst executing it, which looked pretty weird.
Anyways I hope you can help me,
Have a good day y'all ;))
Ah, here's the code: (And the error message beneath it)
from selenium import webdriver
import time
from selenium.webdriver.common.keys import Keys
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(executable_path=r'C:\Users\Anyone\Desktop\Python\chromedriver.exe')
print("Automation Started, please hold on.")
driver.get("https://blablabla")
try:
recap = WebDriverWait(driver, 5).until(
EC.WebDriverException(driver.maximize_window())
)
finally:
driver.forward()
And here's the error message:
Traceback (most recent call last):
File "C:/Users/Anyone/PycharmProjects/blebleble/blablabla.py", line 17, in <module>
EC.WebDriverException(driver.maximize_window())
File "C:\Users\Anyone\PycharmProjects\blablabla\venv\lib\site-packages\selenium\webdriver\support\wait.py", line 71, in until
value = method(self._driver)
TypeError: 'WebDriverException' object is not callable
Don't wait for the Selenium driven ChromeDriver initiated google-chrome Browsing Context to open first and then maximize it.
Instead, add the argument start-maximized and configure the driver, so the Google Chrome Browsing Context opens up maximized using the solution below:
from selenium import webdriver
options = webdriver.ChromeOptions()
options.add_argument("start-maximized")
driver = webdriver.Chrome(options=options, executable_path=r'C:\WebDrivers\chromedriver.exe')
driver.get("https://blablabla")
After making driver object use the below code:-
driver.manage().window().maximize();
and remove the try/finally block.

Selenium log-in on pop-up webpage without HTML

In my Selenium program, I use a google-chrome driver to access and log into my account on this webpage. The problem is that the log-in webpage is a program with a pop-up window and without any HTML code I can grab. Therefore I don't know how to type in my credentials.
I have looked around and have seen several proposals with 'actions' like
actions = ActionChains(driver)
actions.send_keys('skdkds')
actions.perform()
But the problem is that it doesn't type in anything, it only places the cursor in the first field. I guess this is part of the security of the program, but by being able to place the cursor in the right place, I should be able to send keys to the driver and then move along with a tab command. But I don't know how.
For a reproducible example:
from bs4 import BeautifulSoup
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
from webdriver_manager.chrome import ChromeDriverManager
import pandas as pd
import datetime
import time
import glob
import os
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get(link_mentionned_above) //then I am blocked
Updated
As mentionned by Azy_Crw4282, the problem is here handling alerts, however the driver doesn't recognize any alert because for driver.switch_to_alert() I get the error:
File "/usr/local/lib/python3.6/dist-packages/selenium/webdriver/common/alert.py", line 67, in text
return self.driver.execute(Command.W3C_GET_ALERT_TEXT)["value"]
File "/usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/webdriver.py", line 321, in execute
self.error_handler.check_response(response)
File "/usr/local/lib/python3.6/dist-packages/selenium/webdriver/remote/errorhandler.py", line 242, in check_response
raise exception_class(message, screen, stacktrace)
selenium.common.exceptions.NoAlertPresentException: Message: no such alert
Your code below is incorrect since it's not handling the prompt alert explicitly.
actions = ActionChains(driver)
actions.send_keys('skdkds')
actions.perform()
Change it as follows
actions.switchTo().alert().sendKeys("Username");
actions.switchTo().alert().sendKeys("Password");

Python, error with web driver (Selenium)

import time
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
driver = webdriver.Chrome()
driver.get('http://arithmetic.zetamac.com/game?key=a7220a92')
element = driver.find_element_by_link_text('problem')
print(element)
I am getting the error:
FileNotFoundError: [Errno 2] No such file or directory: 'chromedriver'
I am not sure whythis is happening, because I imported selenium already.
Either you provide the ChromeDriver path in webdriver.Chrome or provide the path variable
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys
driverLocation = 'D:\Drivers\chromedriver.exe' #if windows
driver = webdriver.Chrome(driverLocation)
driver.get('http://arithmetic.zetamac.com/game?key=a7220a92')
element = driver.find_element_by_link_text('problem')
print(element)
Best way to eliminate this Exception without altering the code eevn single line is to add the chromedriver.exe( or nay other browser driver files) in to Python
site_packages/scripts directory for windows
dist_package/scripts for Linux
Please check this solution, it works.
If you are using a Mac, then don't include '.exe' I put the selenium package directly into my Pycharm project that I called 'SpeechRecognition'. Then in the selenium file, navigate to: /selenium/webdriver/chrome, then copy and paste the 'chromedriver.exe' file you downloaded most likely from [here][1]
Try this script if you are using PyCharm IDE or similar. This should open a new Google window for you.
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome('/Users/Name/PycharmProjects/SpeechRecognition/selenium/webdriver/chrome/chromedriver')
browser.get('http://www.google.com')
Then if you want to automatically search an item on Google, add these lines below and run. You should see an automatic google search window opening up. It might disappear quickly but to stop that, you can simply add a while loop if you want or a timer
search = browser.find_element_by_name('q')
search.send_keys('How do I search an item on Google?')
search.send_keys(Keys.RETURN)
[1]: https://sites.google.com/a/chromium.org/chromedriver/home

Categories