Write and send Gmail with Selenium for Python - python

I have just started using selenium with Python for the first time, after following a quick tutorial I am now trying to make a program with it that will login to Gmail and then send an email to a chosen email address.
I've gotten the login part done but had some problems with the composing a new email part (only works some of the time) and I get stuck everytime when it comes to writing the message body.
My code is below, I have tried reading the docs but Im having trouble getting the following to work in Gmail and the when I inspect the elements in gmail it seems a lot more complex than the basic html structures in the examples here:
http://selenium-python.readthedocs.org/locating-elements.html#locating-elements-by-tag-name
"""
Write a program that takes an email address and string of text on the command line and then, using Selenium,
logs into your email account and sends an email of the string to the provided address.
"""
import time
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
browser = webdriver.Chrome()
browser.get('http://www.gmail.com')
emailElem = browser.find_element_by_id('Email')
emailElem.send_keys('My_email#gmail.com')
emailElem.submit()
time.sleep(2)
passwordElem = browser.find_element_by_id('Passwd')
passwordElem.send_keys('My_password_here')
passwordElem.submit()
time.sleep(2)
composeElem = browser.find_element_by_class_name('z0') #this only works half of the time
composeElem.click()
time.sleep(7)
toElem = browser.find_element_by_name("to")
toElem.send_keys('my_other_email#gmail.com')
time.sleep(2)
subjElem = browser.find_element_by_name("subjectbox")
subjElem.send_keys('Test with selenium')
time.sleep(2)
bodyElem = browser.find_element_by_???('???') #this is where I get stuck and not sure what to do here
bodyElem.send_keys('A test email with selenium')
time.sleep(2)
sendElem = browser.find_element_by_link_text('send') #not sure if this is correct too
sendElem.submit()

I think the easiest way to select elements on a loaded page is to find them by css selector. You can find them in the browser inspector, and then copy their unique css selector (in firefox press inspect element -> copy unique selector). In this case this should work:
browser.find_element_by_css_selector('#\:nw')

Please Try :
time.sleep(10)
bodyElem = browser.find_element_by_xpath("//*[#id=":ov"]")
OR
bodyElem = browser.find_element_by_xpath("//*[#id=":ou"]")
I assume that it need little more time to find element so I have increased sleep time and also given xpath should work.

As id is changing each time, we can check for aria-label :
browser.find_element_by_css_selector("div[aria-label='Message Body']")
For send, use this :
sendElem = browser.find_element_by_xpath("//div[text()='Send']")
sendElem.click()

You can also hack it using the following once you've found the message box (I'm a noob and couldn't get Send to work)
sendElem.send_keys(Keys.TAB)
sendElem.send_keys(Keys.CONTROL + Keys.RETURN)

Related

How do I fix this error with the "tempmail" api

I'm trying to use the Temp Mail api https://temp-mail.us/en/api/ but whenever I use the given example I'm given an error. I have the api downloaded as well as everything used in it.
from tempmail import TempMail
email = TempMail().get_email_address()
The error:
image
I had the same problem and I couldn't find any solutions, so I had to do it manually.
All I did is opening the tempmail website and copy the email and then switch to the next tab and paste the email.
This code might help
from selenium import webdriver
import time, requests
import clipboard
tempmail = 'https://temp-mail.org'
driver = webdriver.Chrome(os.getcwd()+"\\chromedriver.exe")
delay()
#go to website
driver.get(tempmail)
time.sleep(5)
Copy = driver.find_element_by_xpath('//*[#id="click-to-copy"]')
Copy.click()
email = clipboard.paste()
Then you can open and switch to the next tab using:
driver.execute_script("window.open('');")
driver.switch_to.window(driver.window_handles[1])
After that, you can paste your email
Copy = driver.find_element_by_xpath('XPATH')
Copy.click()
Copy.send_keys(email)

always "wrong password" message in selenium automated login

I'm trying to automate a duolingo login with Selenium with the code posted below.
While everything seems to work as expected at first, I always get an "Wrong password" message on the website after the login button is clicked.
I have checked the password time and time again and even changed it to one without special characters, but still the login fails.
I have seen in other examples that there is sometimes an additional password input field, however I cannot find one while inspecting the html.
What could I be missing ?
(Side note: I'm also open to a completely different solution without a webdriver since I really only want to get to the duolingo.com/learn page to scrape some data, but as of yet I haven't found an alternative way to login)
The code used:
from selenium import webdriver
from time import sleep
url = "https://www.duolingo.com/"
def login():
driver = webdriver.Chrome()
driver.get(url)
sleep(2)
hve_acnt_btn = driver.find_element_by_xpath("/html/body/div/div/div/span[1]/div/div[1]/div[2]/div/div[2]/a")
hve_acnt_btn.click()
sleep(2)
email_input = driver.find_element_by_xpath("/html/body/div[1]/div[3]/div[2]/form/div[1]/div/label[1]/div/input")
email_input.send_keys("email#email.com")
sleep(2)
pwd_input = driver.find_element_by_css_selector("input[type=password]")
pwd_input.clear()
pwd_input.send_keys("password")
sleep(2)
login_btn = driver.find_element_by_xpath("/html/body/div[1]/div[3]/div[2]/form/div[1]/button")
login_btn.click()
sleep(5)
login()
I couldn't post the website's html because of the character limit, so here is the link to the duolingo page: Duolingo
Switch to Firefox or a browser which does not tell the page that you are visiting it automated. See my earlier answer for a very similar issue here: https://stackoverflow.com/a/57778034/8375783
Long story short: When you start Chrome it will run with navigator.webdriver=true. You can check it in console. Pages can detect that flag and block login or other actions, hence the invalid login. This is a read-only flag set by the browser during startup.
With Chrome I couldn't log in to Duolingo either. After I switched the driver to Firefox, the very same code just worked.
Also if I may recommend, try to use Xpath with attributes.
Instead of this:
hve_acnt_btn = driver.find_element_by_xpath("/html/body/div/div/div/span[1]/div/div[1]/div[2]/div/div[2]/a")
You can use:
hve_acnt_btn = driver.find_element_by_xpath('//*[#data-test="have-account"]')
Same goes for:
email_input = driver.find_element_by_xpath("/html/body/div[1]/div[3]/div[2]/form/div[1]/div/label[1]/div/input")
vs:
email_input = driver.find_element_by_xpath('//input[#data-test="email-input"]')

Selenium ChromeDriver not finding elements, while firefox driver can find same elements (Python)

I have been going through the process of learning selenium. I wrote a script using the firefox webdriver that works well. However I am now trying to convert that script to work with headless chrome.
What I wrote:
driver = webdriver.Chrome()
driver.get('https://www.snl.com/web/client?auth=inherit&contextType=external&username=string&enablePersistentLogin=true&OverrideRetryLimit=0&SwitchGetToPostLimit=50000&contextValue=%2Foam&password=secure_string&challenge_url=https%3A%2F%2Fwww.snl.com%2Fweb%2Fclient%3Fauth%3Dinherit&request_id=-2343654539289081584&authn_try_count=0&locale=en_GB&resource_url=https%253A%252F%252Fwww.snl.com%252Finteractivex%252Fdefault.aspx')
time.sleep(14)
login_forms = driver.find_elements_by_class_name('form-control.input-sm.snl-widgets-input-text.snl-selectable.action')
username = login_forms[3]
password = login_forms[4]
username.send_keys('user')
password.send_keys('pass')
I am aware that using time.sleep is not optimal and there are better ways to achieve my wait in selenium. I am going to go back and correct that later.
That said the above code works on snl.com when my webdriver is firefox, but not at all when it is chrome.
I have tried debugging by printing the innerhtml, but chrome returns nothing.
Hoping that somebody out there might have some insight as to what is going wrong here.
Appreciate any help!
To identify the Email address and Password fields the Locator Strategy which you have used looks brittle. You have to adopt a Locator Strategy which uniquely identifies the Email address and Password field through any of the following code blocks :
css_selector :
username = driver.find_element_by_css_selector("input.form-control.input-sm.snl-widgets-input-text.snl-selectable.action[name=username]")
password = driver.find_element_by_css_selector("input.form-control.input-sm.snl-widgets-input-text.snl-selectable.action[name=password]")
username.send_keys('user')
password.send_keys('pass')
xpath :
username = driver.find_element_by_xpath("//input[#class='form-control input-sm snl-widgets-input-text snl-selectable action' and #name='username']")
password = driver.find_element_by_xpath("//input[#class='form-control input-sm snl-widgets-input-text snl-selectable action' and #name='password']")
username.send_keys('user')
password.send_keys('pass')

Access element in default content after switching to iframe in WebDriver

I am practicing with Webdriver in running basic tests, and this specific test is to send an email through Gmail and then assert that it's been received.
I'm using the new version of Gmail where the compose email button pops up a window asynchronously (see picture). To access the body of the email to type a message, I have to select the iframe, but then I am unable to switch out and access the "Send" button element.
There are no other noticeable frames which hold the "Send" button, and using driver.switch_to_default_content() doesn't do anything either. I've included a snippet of the code below.
driver.find_element_by_name("to").clear()
driver.find_element_by_name("to").send_keys("toemailaddy#gmail.com")
localtime = time.asctime( time.localtime(time.time()) )
subj = ("TEST - " + localtime)
print(subj)
driver.find_element_by_name("subjectbox").clear()
driver.find_element_by_name("subjectbox").send_keys(subj)
body = ("TEST")
bodyFrame = driver.find_element_by_xpath("//td[#class='Ap']//iframe")
driver.switch_to_frame(bodyFrame)
driver.find_element_by_xpath("//body[#role='textbox']").clear()
driver.find_element_by_xpath("//body[#role='textbox']").send_keys(body)
driver.find_element_by_xpath("/div[#role='button' and contains(text(), 'Send')]").click()
driver.find_element_by_link_text("Inbox (1)").click()
I can get the message to send by using ActionChains send_keys(Keys.CONTROL, Keys,ENTER).perform(), but would like to figure out how to access the "Send" button to click on it for the sake of my sanity :)
My workaround for elements which have different id every test run is to parse page source with regexp in order to extract the id. Maybe it is not most efficient solution but it works.
import re
pattern = "div id=\"(:\w+)\".*Send</div>"
xpath = ""
matchObj = re.search(pattern,driver.page_source)
if(type(matchObj)!=None):
matchTuple = matchObj.groups()
if(len(matchTuple)>0):
xpath = "//*[#id=\"" + matchTuple[0] + "\"]"
print("SEND button xpath = " + xpath)

How to identify an input box in Selenium Webdriver

I am using Selenium Webdriver for the first time and am running a very simple script, but it is not working. I would like to open Firefox, go to LinkedIn, and enter my email address in the email login field. Using the code below, I'm able to get the first two operations to work, but the script is not properly identifying the email field, and so my email address is never being typed in anywhere.
browser = webdriver.Firefox() #Get local session of firefox
browser.get("http://www.linkedin.com") #Load page
elem = browser.find_element_by_name("session_key-login") #Find the login box
elem.send_keys("email#gmail.com" + Keys.RETURN) #Enter email into login box
How do I correctly identify the email login box and pass it to "elem"?
Try giving
element.send_keys("email#gmail.com");
instead of
elem.send_keys("email#gmail.com" + Keys.RETURN)
How about you just do
elem.send_keys("email#gmail.com")
UPDATE
The identifier used by you was incorrect, you can use either one of the below.
elem = browser.find_element_by_id("session_key-login")
elem = browser.find_element_by_name("session_key")

Categories

Resources