Selenium script to locate textarea element not working - python

I am trying to automate posting into my social media account. I have successfully written the script to log in, after login in I am having difficulty locating the textarea element with which to pass my post, after which I will try to attach an image to my post, make the post and log out. But for now, I am stuck at the locating the textarea after login in. This is the code
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
usernameStr = 'JonJames3872#gmail.com'
passwordStr = 'JamesJon'
textStr = 'Testing my Post'
browser = webdriver.Chrome()
browser.get(('https://accounts.kingsch.at/?client_id=com.kingschat&scopes=%5B%22kingschat%22%5D&redirect_uri=https%3A%2F%2Fweb.kingsch.at%2F'))
# fill in username and password
password = browser.find_element_by_name('password')
password.send_keys(passwordStr)
username = browser.find_element_by_class_name('field')
username.send_keys(usernameStr)
signInButton = browser.find_element_by_class_name('submit-btn')
signInButton.click()
# I HAVE LOGGED IN, NOW THIS IS WHERE MY CODE HAS A PROBLEM
text = browser.find_element_by_xpath("/html/body/div[1]/div/div[2]/div/div[2]/div/div[1]/div/div/div[1]/textarea")
text.send_keys(textStr)
This is the element, from inspect element:
<textarea placeholder="What's happening?" class="KingingBox__input"></textarea>
Textarea HTML Screenshot
URL: https://accounts.kingsch.at/?client_id=com.kingschat&scopes=%5B%22kingschat%22%5D&redirect_uri=https%3A%2F%2Fweb.kingsch.at%2F
Sample User name: JonJames3872#gmail.com (strangely here username is case sensitive)
Sample password: JamesJon
Notification Screenshot

I inserted code to write something in the text area
I inserted code to upload a photo
I inserted code to post your own post
I think 3 out of the 3 questions are all done.
Try this code:
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
import time
import os
path = '/home/avionerman/Documents/stack'
browser = webdriver.Firefox(path)
browser.implicitly_wait(10)
usernameStr = 'JonJames3872#gmail.com'
passwordStr = 'JamesJon'
textStr = 'Testing my Post'
browser.get(('https://accounts.kingsch.at/?client_id=com.kingschat&scopes=%5B%22kingschat%22%5D&redirect_uri=https%3A%2F%2Fweb.kingsch.at%2F'))
# fill in username and password
password = browser.find_element_by_name('password')
password.send_keys(passwordStr)
username = browser.find_element_by_class_name('field')
username.send_keys(usernameStr)
signInButton = browser.find_element_by_class_name('submit-btn')
signInButton.click()
text = browser.find_element_by_class_name('KingingBox__input')
text.clear()
text.send_keys(textStr)
time.sleep(5)
image = browser.find_element_by_class_name('KingingBox__attachment-input').send_keys('/here/path/of_yours/th_574e7c36606306d94a4.jpg')
time.sleep(5)
inserted_photo = browser.find_element_by_class_name('KingingBox__attachments-list')
if inserted_photo.is_displayed():
print("Element found, photo uploaded successfully")
browser.find_element_by_css_selector('.KingingBox__submit-btn').click()
else:
print("Element not found")
At this line:
browser.implicitly_wait(10)
we determine that the browser will wait a max time of 10 seconds for each element to be visible. If the textarea will make more than 10 seconds to appear, the the script will stop. If you see enormous delays increase the seconds of waiting.
Also, as you can see I used this line:
text = browser.find_element_by_class_name('KingingBox__input')
in order to locate the textarea.
In this line:
image = browser.find_element_by_class_name('KingingBox__attachment-input').send_keys('/here/path/of_yours/th_574e7c36606306d94a4.jpg')
I locate the input tag which is responsible for accepting uploades and then I send on it the exact path of the file that I want to upload.
In the last part:
inserted_photo = browser.find_element_by_class_name('KingingBox__attachments-list')
if inserted_photo.is_displayed():
print("Element found, photo uploaded successfully")
browser.find_element_by_css_selector('.KingingBox__submit-btn').click()
else:
print("Element not found")
I save into the inserted_photo variable the element which shows me that the photo uploaded successfully. Then if this variable is displayed this means that the photo uploaded properly. Thus, since we have the text and the photo we are ready to click on the 'Post' button.
Try to use static attributes that are not dynamic and there is no danger of future changes. This way you create stability to your code. Because choosing such an xpath like in your example, is risky. If a div or another tag is going to be excluded or included immediately the xpath is not useful.
PS: I uploaded two posts because of testing, so sorry I couldn't try it other way.

Related

Upload profile picture on Microsoft with selenium, python ()

So, what I'm trying to do is to automate a process which opens the Microsoft login page, enters the login information and then logs in. After that it clicks on the profile and then clicks on change profile picture button.
Now, I'm having trouble with the next part....which is to upload a picture and set it as profile picture.
I searched all over the internet but can't find a solution.
My code till now is -
import time
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 selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
chromedriver = 'C:\\Users\\verma\\Downloads\\chromedriver.exe'
browser = webdriver.Chrome(chromedriver)
action = ActionChains(browser)
#1. Open Microsoft Login Page
browser.get('https://www.microsoft.com/en-in/?wa=wsignin1.0')
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID,"mectrl_headerPicture"))).click()
#2. Login with Username and Password
user = (By.ID,"i0116")
WebDriverWait(browser, 10).until(EC.element_to_be_clickable(user)).send_keys("emailid#outlook.com")
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID,"idSIButton9"))).click()
password = (By.ID,"i0118")
WebDriverWait(browser, 10).until(EC.element_to_be_clickable(password)).send_keys("password")
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID,"idSIButton9"))).click()
#3. Click on Profile and then Click on Change Picture
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID,"mectrl_headerPicture"))).click()
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID,"mectrl_currentAccount_picture_profile_picture"))).click()
#4. Upload Picture
time.sleep(5)
browser.quit()
What I have tried is -
#4. Upload Picture
WebDriverWait(browser, 30).until(EC.element_to_be_clickable((By.ID,"id__62"))).click()
The windows file chooser is not popping up. My guess is that I gave wrong ID for "Choose File" button/link to selenium and that's why it gives TimeoutException since it cant find the element.
But I cant seem find the correct ID. I also want to know how to upload the picture after the File Chooser pops up successfully.
EDIT: Screenshot of the HTML code (Through Inspect)
HTML Code
There are few steps that you need to follow in order to upload a pic :
you need to switch driver focus to new tab
Click on Add a photo.
Upload a pic.
Assert Successful Message.
Code :
#4. Upload Picture
windows_before = browser.current_window_handle
WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.ID,"mectrl_currentAccount_picture_profile_picture"))).click() # this is from #3
windows_after = browser.window_handles
new_window = [x for x in windows_after if x != windows_before][0]
browser.switch_to.window(new_window)
browser.find_element(By.CSS_SELECTOR, "button[id='profile.profile-page.profile-pic-section.edit-picture']").click()
browser.find_element(By.CSS_SELECTOR, "button[id='button[id='profile.edit-picture.upload-button']']").click()
browser.find_element(By.CSS_SELECTOR, "input[type='file']").send_keys("path of the file to be uploaded")
#Assert your msg

Python Selenium: Can't Get HREF Link Off Instagram in <time> tags

PostLinkExtraction = driver.find_element_by_xpath("//article[1]/div[3]/div[1]/div/div[2]/div[1][*[local-name()='a']]").get_attribute('href')
print (PostLinkExtraction)
Im trying to print the href link from the Time Stamp on Instagram under the first post on my Instagram Timeline. The code above returns none for some reason. Below is the code for anyone who wants to run it and see where I may have went wrong, but the overall goal I want to accomplish is to extract the href link from the <-time> tags. Below is an image of where the <-time> tags will be in developer tools
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from time import sleep
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
user = 'username'
passw = 'password'
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://www.instagram.com/')
driver.implicitly_wait(10)
driver.find_element_by_name('username').send_keys(user)
driver.find_element_by_name('password').send_keys(passw)
Login = "//button[#type='submit']"
sleep(2)
driver.find_element_by_xpath(Login).submit()
sleep(1)
# Logs into Instagram
print ('Logged In')
#------------------------ATTENTION
NotNow = "//button[contains(text(),'Not Now')]"
driver.find_element_by_xpath(NotNow).click()
# Clicks Pop Up
print ('Close Pop Up')
# It's weird but the pop up opens once, only after this page.
# If ever a problem delete one, or have the first click be
# directed to your Instagram Profiles timeline
NotNow = "//button[contains(text(),'Not Now')]"
driver.find_element_by_xpath(NotNow).click()
#Clicks Pop Up; Comment out the line above if it causes an error
print ('Close Pop Up')
#-----------------------------------
driver.refresh()
print ('refreshing')
driver.implicitly_wait(10)
PostLinkExtraction = driver.find_element_by_xpath("//article[1]/div[3]/div[1]/div/div[2]/div[1][*[local-name()='a']]").get_attribute('href')
print (PostLinkExtraction)
I find out the issue is because of your xpath. Fix it and you will print out the href of your first post.
PostLinkExtraction = driver.find_element_by_xpath("//article[1]/div[3]/div[1]/div/div[2]/div[1]/a").get_attribute('href')
print (PostLinkExtraction)
The result:
Short Answer: Stop sticking to xpaths and find the elements you're looking for in this way:
1 - put all the elements with the same tag in an array
2 - search for two-three attributes that renders it unique
3- extract it cycling in the array and use it
Easy, fast and clean.

How to skip WebDriverWait if it is not True?

A bit bad in English. I am just making a simple Instagram bot that first takes usernames and passwords from the txt file and put it to login in the website, But "Turn on Notification" pop up only in the first login. Whenever bot login with the second account it does not pop up. I want my WebdriverWait to ignore if it does not find any element. I want it to ignore if "Turn on Notification" does not pop up in other accounts.
My code to remove Turn on Notification pop up:
pop_up = ui.WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".aOOlW.HoLwm"))).click() # Remove notification
sleep(4)
My whole code:
from time import sleep
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from getpass import getpass
from selenium.webdriver.support import ui
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# Create a list of username, password pairs from your file.
username_password_list = list()
with open("C:\\Users\\user\\AppData\\Roaming\\JetBrains\\PyCharmCE2020.1\\scratches\\detail.txt") as file:
for line in file:
user, password = line.split(':')
username_password_list.append((user, password))
browser = webdriver.Firefox() # Runs Firefox.
browser.implicitly_wait(5)
browser.get('https://www.instagram.com/') # Web address to load.
for user, password in username_password_list:
class Main:
username_input = browser.find_element_by_css_selector('input[name="username"]') # Finds username field.
password_input = browser.find_element_by_css_selector('input[name="password"]') # Finds password field.
username_input.send_keys(user) # Input username.
password_input.send_keys(password) # Input password.
login_button = browser.find_element_by_xpath('//button[#type="submit"]') # Finds login button.
login_button.click() # Click login button.
pop_up = ui.WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.CSS_SELECTOR, ".aOOlW.HoLwm"))).click() # Remove notification.
sleep(4)
class SearchBar:
Search = browser.find_element_by_xpath('//input[contains(#class, "XTCLo x3qfX")]') # Find search bar.
Search.send_keys("Any_Username") # Input.
browser.find_element_by_class_name("yCE8d").click() # Search.
sleep(5)
browser.find_element_by_xpath('//span[#class="vBF20 _1OSdk"]').click() # Finds follow button and click.
sleep(5)
class Logout:
browser.find_element_by_xpath('//*[#id="react-root"]/section/nav/div[2]/div/div/div[3]/div/div[5]').click() # Go to profile.
sleep(5)
browser.find_element_by_xpath('//*[#id="react-root"]/section/main/div/header/section/div[1]/div/button').click() # Click settings.
sleep(5)
browser.find_element_by_xpath('/html/body/div[4]/div/div/div/button[9]').click() # Click logout.
sleep(5)
browser.close()
You can do it with try/except block:
try:
ui.WebDriverWait(browser, 10).until(EC.visibility_of_element_located(
(By.CSS_SELECTOR, ".piCib")))
ui.WebDriverWait(browser, 5).until(EC.element_to_be_clickable(
(By.CSS_SELECTOR, ".aOOlW.HoLwm"))).click()
except:
pass
except block will be executed after a 5-sec timeout when there is no pop-up.
I hope it helps you!

Python Selenium: Microsoftonline login not working correctly

I'm trying to login to Office 365 Outlook using Python Selenium, that redirects for 2 factor Auth.
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
email_ID = "YourEmail#Gmail.com"
Password = "Password"
driver = webdriver.Chrome(executable_path="C:\pythonLibs\chromedriver\chromedriver.exe")
driver.set_page_load_timeout(10)
driver.get("https://outlook.office365.com/mail/inbox")
try:
element = WebDriverWait(driver, 10).until
(
# EC.presence_of_element_located((By.ID, "myDynamicElement"))
EC.url_contains("login.microsoftonline.com/common/oauth2/authorize")
)
finally:
print("2nd Login Page Reached.")
print(driver.current_url)
# Login
driver.find_element_by_id("i0116").send_keys(email_ID)
# driver.find_element_by_id("i0118").send_keys(Password) #passwordBrowserPrefill
print("Login Entered")
driver.find_element_by_xpath('//*[#id="idSIButton9"]').submit()
On the the 1st page redirect (2nd Page) after entering email and submitting, it hits me with a page of
Sign in
Sorry, but we’re having trouble with signing you in.
AADSTS90100: login parameter is empty or not valid.
If I comment out the submit, and click Next manually after email has been entered it works as normal.
I have previously tried adding an implicit wait before submitting, but to no avail
I look forward to your suggestions.
Try:
driver.find_element_by_xpath('//*[#id="idSIButton9"]').click()
Instead of:
driver.find_element_by_xpath('//*[#id="idSIButton9"]').submit()
Because it seems that you're submitting the login form before all the required values are entered.

Python selenium issue: able to find element but not send_keys

I am trying to login into the ESPN footytips website so that I can scrape information for one of my leagues.
I am having no issues opening an instance of Chrome and navigating to the homepage (which contains the login form) and can even select the username field but I cannot for the life of me send my login details to the form.
In debugging I know I can find and select the form submit button and the issue seems to be in passing my login details using send_keys as my exception rule always triggers after I attempt call send_keys.
Any suggestions on how to resolve would be welcomed! My script is below:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
login_address = "http://www.footytips.com.au/home"
me_login = "test#test.com"
me_password = "N0TMYR3#LP#S5W0RD"
browser = webdriver.Chrome()
browser.get(login_address)
try:
login_field = browser.find_element_by_id("ft_username")
password_field = browser.find_element_by_id("ft_password")
print("User login fields found")
login_field.send_keys(me_login)
password_field.send_keys(me_password)
print("Entered login data")
submit_button = browser.find_element_by_id("signin-ft")
print("Submit button found")
submit_button.submit()
except:
print("Error: unable to enter form data")
The locators you have used doesn't uniquely identifies the login_field and the password_field. Additionally you need to wait for the respective WebElements to be visible. Here is your own code with some tweaks :
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
#lines of code
login_address = "http://www.footytips.com.au/home"
me_login = "test#test.com"
me_password = "N0TMYR3#LP#S5W0RD"
browser.get(login_address)
login_field = WebDriverWait(browser, 10).until(EC.element_to_be_clickable((By.XPATH,"//div[#class='login-form']//input[#id='ft_username']")))
password_field = browser.find_element_by_xpath("//div[#class='login-form']//input[#id='ft_password']")
login_field.send_keys(me_login)
password_field.send_keys(me_password)
print("Entered login data")

Categories

Resources