Home > other >  Login to user account with Selenium
Login to user account with Selenium

Time:03-12

I am trying to log to my Garmin Connect account using selenium/python in PyCharm. I know there is an API but, as this is for training purpose, I really would like to reach my goal through the Website.

My code:

import scrapy
import time
from scrapy_selenium import SeleniumRequest
from scrapy.selector import Selector

from selenium.webdriver.support.ui import WebDriverWait as wait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains

class ScrapgarminSpider(scrapy.Spider):
name = 'scrapGarmin'

def start_requests(self):
    yield SeleniumRequest(
        url='https://connect.garmin.com/signin/',
        wait_time=3,
        callback=self.parse
    )

def parse(self, response):
    driver = response.meta['driver']

    wait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, "//iframe[@id='gauth-widget-frame-gauth-widget']")))

    frameLogin=driver.find_element_by_xpath("//iframe[@id='gauth-widget-frame-gauth-widget']")
    
    driver.switch_to.frame(frameLogin)

    champLogin=driver.find_element_by_xpath("//input[@class='login_email']")
    champLogin.send_keys("my_email_here")
    driver.implicitly_wait(3)

    champPassword = driver.find_element_by_xpath("//input[@id='password']")
    champPassword.send_keys("my_password_here")
    time.sleep(5)

    boutonSubmit = driver.find_element_by_xpath("//button[@type='submit']")
    boutonSubmit.click()

    time.sleep(5)
    print(f"Current URL: {driver.current_url}")

If I do this, I have a:

selenium.common.exceptions.ElementClickInterceptedException: Message: element click intercepted: Element <iframe 

Then I tried to click using javascript:

boutonSubmit = wait(driver, 10).until(EC.visibility_of_element_located((By.XPATH, "//button[@type='submit']")))
        driver.execute_script("arguments[0].click();", boutonSubmit)

In that case, there is no error message by my current URL remains the signin page. It does not enter the website.

Any idea please ? That would really help. Thanks

CodePudding user response:

Why just not simplifying your code instead, you can make a lot of improvements. You may have your preferences but here is a simplified script with my methods. No need to set classes, multiple functions and setting variables for each action. I also see that you are using scrapy but you can also just install and use the chrome driver. All you have to do is download chromium chromedriver at https://chromedriver.chromium.org/downloads and then replace the path in webdriver.Chrome(executable_path="Replace with chromedriver path").

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

#setting up driver and loading page
driver = webdriver.Chrome(executable_path="Replace with chromedriver path")
driver.get("https://connect.garmin.com/signin/") #loading page
wait = WebDriverWait(driver, 20) #defining webdriver wait

#defining username and password, dont remove \n
username = 'xxx'
password = 'xxx\n' #\n will act as an enter key and automatically login after having entered the password without clicking on confirm

#locating the login script under a function to make things more "visible"
def login():
    wait.until(EC.visibility_of_element_located((By.XPATH, "//iframe[@id='gauth-widget-frame-gauth-widget']")))
    frameLogin = driver.find_element(By.XPATH, "//iframe[@id='gauth-widget-frame-gauth-widget']")
    driver.switch_to.frame(frameLogin)
    wait.until(EC.visibility_of_element_located((By.ID, 'username'))).send_keys(username) #userame/email
    wait.until(EC.visibility_of_element_located((By.ID, 'password'))).send_keys(password) #password

#calling the login function and printing "you're in!!" when logged in
login()
print("you're in!!")
print('Url: ', driver.current_url)

You can locate elements by ID, or NAME which are much more simple and shorter than the XPATH. I can also see that you define vairiables which is ok but then you 're-call' the variable adding a .send_keys function, you can simply add it at the end:

test = driver.find_element(By.XPATH, "xxx")
test.send_keys("hello")

to

test = driver.find_element(By.XPATH, "xxx").send_keys("hello")

You can also remove the variable and just make a little # note of the function.

driver.find_element(By.XPATH, "xxx").send_keys("hello") #test

I also recommend using the driver.wait function which is brilliant to not get any errors or having to wait extra time with time.sleep() for example, as you see I define the waiting function at the beginning.

wait.until(EC.visibility_of_element_located((By.XPATH,'xxx'))).send_keys(hello)` #test

Some more tips to learn selenium:

  • do not stay stuck in the tutorial hell, make projects, preferably on your own or patchwork
  • take notes or speccific scripts when you learn something new
  • some projects ideas: type bot on online type learning sites, auto clicker etc...
  • just have fun while learning

Simple and effective, have a nice day.

CodePudding user response:

Thanks for your answers. I know my code is not optimized. I'm a dummy :) Few remarks: I tried wait:

  • element_to_be_clickable
  • visibility_of_element_located
  • presence_of_element_located
  • frame_to_be_available_and_switch_to_it

None of the them work. In the login function which is proposed hereabove, I see an input of the login and password. But it does not solve my issue on clicking the submit button to log in.

I am still stuck :(

  • Related