This question already has answers here:
selenium python send_key error: list object has no attribute
(9 answers)
Closed 3 years ago.
I am making a Twitter bot that can automatically login when I run the script. But whenever I run the script, I get this an error that I cannot find any solutions for. Does anyone have an idea of how to fix it?
I tried to change element to elements and send_keys to send_Keys but it won't work
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
class TwitterBot:
def __init__(self,username,password):
self.username = username
self.password = password
self.bot = webdriver.Firefox()
def login(self):
bot = self.bot
bot.get('https://twitter.com/')
time.sleep(3)
email = bot.find_elements_by_class_name('email-input')
password = bot.find_elements_by_class_name('session[password]')
email.clear()
password.clear()
email.send_keys(self.username)
password.send_keys(self.password)
password.send_keys(Keys.RETURN)
ed = TwitterBot('EMAIL HERE', 'PASSWORD HERE')
ed.login()
I hope to get it logging in so I can work further on my project.
find_elements_by_xxx will return list of elements and you can't perform the send_keys operation on the list. Instead you have to use find_element_by_xxx which will return a single element, then you can perform element based operations.
If you want to get the list of element and then perform the operation on any specific element then you can use below logic.
elements = driver.find_elements_by_xxx("locator")
# perform operation on the first matching element
elements[0].send_keys("value_goes_here")
# if you want to perform operation on the last matching element
element[-1].send_keys("value_goes_here")
I now know what I messed up:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
class TwitterBot:
def __init__(self,username,password):
self.username = username
self.password = password
self.bot = webdriver.Firefox()
def login(self):
bot = self.bot
bot.get('https://twitter.com/')
time.sleep(3)
email = bot.find_element_by_name('session[username_or_email]')
password = bot.find_element_by_name('session[password]')
email.clear()
password.clear()
email.send_keys(self.username)
password.send_keys(self.password)
ed = TwitterBot('EMAIL HERE', 'PASSWORD HERE')
ed.login()
On the line email = bot.find_element_by_name('session[username_or_email]')
it was first bot.find_element_by_class_name('session[username_or_email]')
Feeling stupid. Thanks for the help guys!
Related
selenium ,how to send emoji to sender in WhatsApp with send_keys()? . i dont want to send emoji by clicking on that emoji button ,but i want to like just copy the emoji which has been sent to us in text message of whatsapp and send that same emoji to sender . i have tried this as helped by #cruisepandey
chats = driver.find_elements_by_css_selector("img[data-plain-text][crossorigin='anonymous']")
for chat in chats:
print(chat.get_attribute('alt'))
this above code prints all the emojis of a chat. But by using this code this gives an error of
chats = driver.find_elements_by_css_selector("img[data-plain-text][crossorigin='anonymous']")
for chat in chats:
print(chat.get_attribute('alt'))
type = driver.find_element_by_xpath('//div[#data-tab="6"]')
type.send_keys(chat.get_attribute('alt'))
this code gives an error = Message: unknown error: ChromeDriver only supports characters in the BMP
chats = driver.find_elements_by_css_selector("img[data-plain-text][crossorigin='anonymous']")
for chat in chats:
print(chat.get_attribute('alt'))
type = driver.find_element_by_xpath('//div[#data-tab="6"]')
pyperclip.copy(chat.get_attribute('alt'))
type.send_keys(Keys.CONTROL + "V")
time.sleep(1)
i tried this code to send emoji but this by using this actually it works but it sends twice in whatsapp typebar but prints only once in terminal for a particular emoji for eg it prints this in terminal "🔥" and same code types this in whatsapp typebar "🔥🔥" . CAN ANYONE HELP ME WHY IT IS PRINTING TWICE IN WHATSAPP TYPEBAR BUT ONLY ONCE IN TERMINAL ??? i also want to append that emoji into a list ,but when appending that emojis ,after printing list ,it gives a list with elements ="None" . This is complete code
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
import time
import pyperclip
driver = webdriver.Chrome(r'C:\Users\PRANAV PATIL\Downloads\chromedriver.exe')
driver.get(r'https://web.whatsapp.com/')
searchbox = WebDriverWait(driver,
10).until(expected_conditions.presence_of_element_located((By.XPATH,
"//div[#id='side']//div//div//label//div//div[#contenteditable='true']")))
searchbox.send_keys('') #enter your sender's name
searchbox.send_keys(Keys.RETURN)
time.sleep(2)
chats = driver.find_elements_by_css_selector("img[data-plain-text][crossorigin='anonymous']")
for chat in chats:
print(chat.get_attribute('alt'))
type = driver.find_element_by_xpath('//div[#data-tab="6"]')
pyperclip.copy(chat.get_attribute('alt'))
type.send_keys(Keys.CONTROL + "V")
time.sleep(1)
Regarding that typing twice : Instead of type.send_keys(Keys.CONTROL + "V"), try like below. It worked for me.
type.send_keys(Keys.CONTROL+"v")
So basically, you want to send_keys to type
Did you try this :
type = driver.find_element_by_xpath('//div[#data-tab="6"]')
type.send_keys(chat.get_attribute('alt'), Keys.RETURN)
Update 1 :
Looks like you cannot simply send special character like emoji to chromedriver, try changing your browser (change to Firefox and see if that helps) should help you past this issue.
also, if you wanna stick with Chrome, you can give it a try like this :
JS_ADD_TEXT_TO_INPUT = """
var elm = arguments[0], txt = arguments[1];
elm.value += txt;
elm.dispatchEvent(new Event('change'));
"""
type = driver.find_element_by_xpath('//div[#data-tab="6"]')
driver.execute_script(JS_ADD_TEXT_TO_INPUT, type, chat.get_attribute('alt'))
Update 2 :
Using FireFox :
driver = webdriver.Firefox(executable_path = "D:\geckodriver.exe")
driver.maximize_window()
driver.implicitly_wait(30)
driver.get("https://web.whatsapp.com/")
wait = WebDriverWait(driver, 20)
try:
searchbox = WebDriverWait(driver,10).until(EC.visibility_of_element_located((By.CSS_SELECTOR, "div[class*='copyable-text selectable-text']")))
searchbox.send_keys('Anvesh') # enter your sender's name
searchbox.send_keys(Keys.RETURN)
print('search was successful')
except:
print('there were some error while searching for name')
pass
time.sleep(2)
chats = driver.find_elements_by_css_selector("img[data-plain-text][crossorigin='anonymous']")
for chat in chats:
print(chat.get_attribute('alt'))
type = driver.find_element_by_xpath('//div[#data-tab="6"]')
type.send_keys(chat.get_attribute('alt'))
time.sleep(1)
I'm learning about selenium on python and came across an error I don`t really know how to solve:
In this project the bot I've designed was supossed to Like all the tweets on the page when I searched for a certain subject. Altought the bot go through all the loops and like half of the tweets, it still misses every 2 or 3 tweets. Could somebody shed a light on why is it missing tweets?
# it's essencial that the user first pip install selenium on his system or on the source code editor such as visual code
# afterwards download the latest geckodriver on github and unzip it on the root of your python folder
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
class TwitterBot:
def __init__(self,username,password):
self.username = username
self.password = password
self.bot = webdriver.Firefox()
def login(self):
bot = self.bot
bot.get('https://twitter.com/login')
time.sleep(5) # I used a timer to load wait for the page to load before entering the login and password
email = bot.find_element_by_name("session[username_or_email]")
password = bot.find_element_by_name("session[password]")
email.clear()
password.clear()
email.send_keys(self.username)
password.send_keys(self.password)
password.send_keys(Keys.RETURN)
time.sleep(5)
def like_tweet(self,hashtag):
bot = self.bot
bot.get('https://twitter.com/search?q='+hashtag+'&src=typeahead_click')
time.sleep(3)
bot.find_element_by_link_text("Latest").click()
time.sleep(3)
for i in range(6):
bot.execute_script('window.scrollTo(0,document.body.scrollHeight)')
time.sleep(3)
tweets = bot.find_elements_by_xpath('//div[#data-testid="tweet"]')
for tweet in tweets:
try:
bot.find_element_by_xpath('//div[#data-testid="like"]').click()
time.sleep(3)
except:
print("ERROR")
bot = TwitterBot('xxx#gmail.com','xxxxx') # Enter here your username/e-mail and password like this: ('email#email.com','password')
bot.login()
bot.like_tweet('python learning') # Enter here the subject you want the bot to search for ('subject')
I have an Instagram robot class that takes the username and password and logs in to the account.
I wrote a comment function in this class to put the comment below the post, I use this function but when it opens a custom post, when I leave a comment I get an error.
I do not know the reason for this error
Please let me know if anyone knows a solution
my code:
from selenium import webdriver
import time
import random
class InstaBot:
#Create a contractor to open the browser and get the username and password of your Instagram account
def __init__(self,username,password):
self.driver = webdriver.Firefox()
self.username = username
self.password = password
#This function is used to login to your Instagram account
def login(self):
driver = self.driver
#Open the browser and open the Instagram site
driver.get('https://www.instagram.com')
#Find the username box address via XPath
user_box = driver.find_element_by_xpath('//*[#id="loginForm"]/div/div[1]/div/label/input')
#Find the password box address via XPath
password_box = driver.find_element_by_xpath('//*[#id="loginForm"]/div/div[2]/div/label/input')
#Find the login button via Xpath
button = driver.find_element_by_xpath('//*[#id="loginForm"]/div/div[3]')
#Click on the username box
user_box.click()
#And enter the username in the username box
user_box.send_keys(self.username)
time.sleep(5)
#Click on the password box
password_box.click()
#And enter the password in the password box
password_box.send_keys(self.password)
time.sleep(5)
#Finally, click the Login button
button.click()
time.sleep(5)
#Go to the home page by adding a username to continue the Instagram link
acount = driver.get('https://www.instagram.com/%s/'%(self.username))
def comment(self,message=None):
driver = self.driver
driver.get('https://www.instagram.com/p/CLP-HN9AP0i/')
coment_box = driver.find_element_by_xpath('/html/body/div[1]/section/main/div/div[1]/article/div[3]/section[3]/div/form/textarea').click()
coment_box.send_keys(message)
mobin = InstaBot('your user name','your password')
mobin.login()
time.sleep(5)
mobin.comment('Very Good')
The error it gives me:
Traceback (most recent call last):
File "C:\Users\Mobin\Desktop\test_projcet.py", line 50, in <module>
mobin.comment('Very Good')
File "C:\Users\Mobin\Desktop\test_projcet.py", line 45, in comment
coment_box.send_keys(message)
AttributeError: 'NoneType' object has no attribute 'send_keys'
Problem
The problem it you are setting your comment_box equal to an driver action not a web element. It will send out error "object has no attribute 'send_keys'" because it not an web element.
Also your comment_box is load more than one time. So you need to declare comment_box again after clicking it the first time.
Solution
remove click at the end of this line
coment_box = driver.find_element_by_xpath('your xpath').click()
replace with this code, it should work:
coment_box = driver.find_element_by_xpath('your xpath')
coment_box.click()
time.sleep(5)
coment_box_2 = driver.find_element_by_xpath('your xpath')
coment_box.send_keys(message)
So I do realize that using gmail api is the best solution, but due to the gmail account having restrictions (school) I can't actually use the api. So while I was searching for the solution I have found about selenium.
I haven't actually found a tutorial about how to filter emails/click on emails that is within 24 hours (which I think I can set it up myself) and click on emails with an link attached (google.meet)
Since the subject isn't always the same nor the sender, I can't actually limit it to the subject and email, so need help with some kind of email body filter.
import webbrowser
from selenium import webdriver
import time
import email
import imaplib
import sys
import datetime
import smtplib
with open('accountdetail.txt', 'r') as file:
for details in file:
username,password = details.split(':')
# create a new Chrome session
driver = webdriver.Chrome('C:\driver\chromedriver.exe')
driver.implicitly_wait(30)
driver.maximize_window()
# navigate to the application home page
driver.get("https://accounts.google.com/")
#get the username textbox
login_field = driver.find_element_by_name("identifier")
login_field.clear()
#enter username
login_field.send_keys(username)
login_field.send_keys(u'\ue007') #unicode for enter key
time.sleep(4)
#get the password textbox
password_field = driver.find_element_by_name("password")
password_field.clear()
#enter password
password_field.send_keys(password)
password_field.send_keys(u'\ue007') #unicode for enter key
time.sleep(10)
#navigate to gmail
driver.get("https://mail.google.com/")
I have found this resources, but for some reason they only work with subject and doesn't actually click on email with a link.
How to click on a Particular email from gmail inbox in Selenium?
https://www.youtube.com/watch?v=6VJaWtz6kzs
If you have the exact link, you can get the element using XPath and click:
url = r'YOUR URL, FROM ANY VARIABLE'
driver.find_element_by_xpath('//a[#href="'+url+'"]').click()
I have decided to attempt to create a simple web scraper script in python. As a small challenge I decided to create a script which will be able to log me into facebook and fetch the current birthdays displayed in the side. I have managed to write a script which is able to log me into my facebook, however I have no idea how to fetch the birthdays displayed.
This is my scrypt.
from selenium import webdriver
from time import sleep
from webdriver_manager.chrome import ChromeDriverManager
from selenium.webdriver.chrome.options import Options
usr = 'EMAIL'
pwd = 'PASSWORD'
driver = webdriver.Chrome(ChromeDriverManager().install())
driver.get('https://www.facebook.com/')
print ("Opened facebook")
sleep(1)
username_box = driver.find_element_by_id('email')
username_box.send_keys(usr)
print ("Email Id entered")
sleep(1)
password_box = driver.find_element_by_id('pass')
password_box.send_keys(pwd)
print ("Password entered")
login_box = driver.find_element_by_id('u_0_b')
login_box.click()
print ("Login Sucessfull")
print ("Fetched needed data")
input('Press anything to quit')
driver.quit()
print("Finished")
This is my first time creating a script of this type. My assumption is that I am supposed to traverse through the children of the "jsc_c_3d" div element until I get to the displayed birthdays. Furthermore the id of this element changes everytime the page is refreshed. Can anyone tell me how this is done or if this is the right way that I should go on about solving this problem?
The div for the birthday after expecting elements:
<div class="" id="jsc_c_3d">
<div class="j83agx80 cbu4d94t ew0dbk1b irj2b8pg">
<div class="qzhwtbm6 knvmm38d"><span class="oi732d6d ik7dh3pa d2edcug0 qv66sw1b c1et5uql
a8c37x1j muag1w35 enqfppq2 jq4qci2q a3bd9o3v knj5qynh oo9gr5id hzawbc8m" dir="auto">
<strong>Bobi Mitrevski</strong>
and
<strong>Trajce Tusev</strong> have birthdays today.</span></div></div></div>
You are correct that you would need to traverse through the inner elements of jsc_c_3d to extract the birthdays that you want. However this whole automated web-scraping is a problem if the id value is dynamic, such that it changes on each occasion. In this case, text parsers such as bs4 would do the job.
With the bs4 approach you simply have to extract the relevant div tags from the DOM and then you can parse the data to obtain the required contents.
More generally, this problem is solvable using the Facebook-API which could be as simple as
import facebook
token = 'a token' # token omitted here, this is the same token when I use in https://developers.facebook.com/tools/explorer/
graph = facebook.GraphAPI(token)
args = {'fields' : 'birthday,name' }
friends = graph.get_object("me/friends",**args)