Use case:
Sending out automated WhatsApp messages using pythonanywhere. Step by step logic below:
non-coders write on a gsheet the phone numbers to which we should
send out the messages
the gsheet data is read (using gspread in pythonanywhere)
open WhatsApp URL to send out the messages in bulk
I have a code using selenium running on my machine that opens the web whatsapp url, finds the needed elements on the website, and sends the messages to the gsheets phone numbers - find below a snippet from that part of the code that I am using on my machine:
global driver
driver.get('https://web.whatsapp.com/')
waiter.until(EC.title_is("WhatsApp"))
waitCounter = 0
while 1:
try:
waiter.until(EC.presence_of_element_located((By.XPATH, "//canvas[#aria-label='Scan me!']")))
waitCounter+=1
if waitCounter%1000 == 0:
print("Waiting for user to log in...", 'WARNING')
except:
print("Logged in to WhatsApp")
break
for entry in data:
driver.find_element_by_xpath(PHONE_NUMER_INPUT).send_keys(str(entry['PhoneNumber']))
time.sleep(2)
driver.find_element_by_xpath(PHONE_NUMER_INPUT).send_keys(Keys.ENTER)
time.sleep(2)
driver.find_element_by_class_name('p3_M1').send_keys(str(entry['Message']))
time.sleep(2)
driver.find_element_by_class_name('_4sWnG').click()
time.sleep(2)
Doubt:
To make step nr 3. working on python anywhere I would have to use a headless browser. However, to initiate whatsapp web we always need to do the QR code scan, so I am not being able to do it that way. Find below the current (useless) part of my code with the headless selenium code - (NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[#id='side']/div[1]/div/label/div/div[2]"}). I am quite stuck here. Any tip or idea to overcome this is more than welcome and happy to discuss any possible solutions using other libraries that you guys might find appropriate.
Thanks in advance.
chrome_options = webdriver.ChromeOptions()
chrome_options.add_argument("--headless")
chrome_options.add_argument("--disable-gpu")
driver = webdriver.Chrome(options=chrome_options)
def send_whatsapp_message():
global driver
driver.get('https://web.whatsapp.com/')
print("Done updating, check the spreadsheet now")
#redirect('https://web.whatsapp.com/', code=302)
for entry in data:
driver.find_element_by_xpath("//*[#id='side']/div[1]/div/label/div/div[2]").send_keys(str(entry['PhoneNumber']))
time.sleep(2)
driver.find_element_by_xpath("//*[#id='side']/div[1]/div/label/div/div[2]").send_keys(Keys.ENTER)
time.sleep(2)
driver.find_element_by_class_name('p3_M1').send_keys(str(entry['Message']))
time.sleep(2)
driver.find_element_by_class_name('_4sWnG').click()
time.sleep(2)
print("Successfully send message to {0}, name: {1}".format(str(entry['PhoneNumber']), str(entry['Name'])), 'INFO')
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 am learning Python and I am trying things with Selenium. Today I am trying to retrieve a message from the Spectrum chat of Star Citizen: https://robertsspaceindustries.com/spectrum/community/SC/lobby/1
I would like to retrieve the: div class="lobby-motd-message" because it gives good information.
This is my code but when I run it, it displays nothing... Can you help me to solve this problem ? Please. I will do more things with Selenium ( a Discord bot) but I need to retrieve this information first.
#!/usr/bin/python3
from selenium import webdriver
from selenium.webdriver.firefox.options import Options
opts = Options()
opts.headless = True
browser = webdriver.Firefox(options=opts)
url = "https://robertsspaceindustries.com/spectrum/community/SC/lobby/1"
browser.get(url)
browser.implicitly_wait(10)
try:
info = browser.find_element_by_class_name("lobby-motd-message")
print(info.text)
except:
print("not found")
browser.close()
quit()
Depending on what element you want you might need to target and get it's text.
try:
info = browser.find_element_by_class_name("lobby-motd-message")
print(info.find_element_by_tag_name('p').text)
except:
print("not found")
Outputs
Star Citizen Alpha 3.11 is LIVE - Discover more here !
All of it
print(info.get_attribute('innerHTML'))
Outputs
<p>Star Citizen Alpha 3.11 is LIVE - Discover more here !</p>
I posted recently about some trouble I was having with selenium, primarily the anticaptcha API. Ive managed to solve that but I am having some trouble over here. This is my current code:
from time import sleep
from selenium import webdriver
from python_anticaptcha import AnticaptchaClient, NoCaptchaTaskProxylessTask
import os
import time
#Gather Api Key
api_key = 'INSERT API KEY HERE'
#Go to the acc registration site
browser = webdriver.Chrome()
browser.implicitly_wait(5)
browser.get('https://www.reddit.com/register/')
sleep(2)
#Input email
email_input = browser.find_element_by_css_selector("input[name='email']")
email_input.send_keys("INSERT EMAIL HERE")
#Continue to the next part of the registration process
continue_button = browser.find_element_by_xpath("//button[#type='submit']")
continue_button.click()
#Find and input the username and password fields
username_input = browser.find_element_by_css_selector("input[name='username']")
password_input = browser.find_element_by_css_selector("input[name='password']")
username_input.send_keys("INSERT USERNAME HERE")
password_input.send_keys("INSERT PASSWORD HERE")
#Gather site key
url = browser.current_url
site_key = "6LeTnxkTAAAAAN9QEuDZRpn90WwKk_R1TRW_g-JC"
#Acc do the solving process
client = AnticaptchaClient(api_key)
task = NoCaptchaTaskProxylessTask(url, site_key)
job = client.createTask(task)
print("Waiting for recaptcha solution")
job.join()
# Receive response
response = job.get_solution_response()
print(response)
print("Solution has been gotted")
# Inject response in webpage
browser.execute_script('document.getElementById("g-recaptcha-response").innerHTML = "%s"' % (response))
print("Injecting Solution")
# Wait a moment to execute the script (just in case).
time.sleep(1)
print("Solution has been gotted for sure")
# Press submit button
browser.implicitly_wait(10)
Signup = browser.find_element_by_xpath('//input[#type="submit"]')
Signup.click()
Everything runs smoothly except for the final line. I think the program is recognizing the submit button but for some reason gives an element not interactable error. Any help on how to solve this would be greatly appreciated
I had the same issue when I was using selenium. Sometimes it happens that even though selenium has recognized the element, its function is not "ready." Adding a delay before clicking the submit button should fix the issue.
I would like to send a :heart: emoji with selenium's send_keys()
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
driver = webdriver.Chrome('./chromedriver')
driver.get("https://web.whatsapp.com/")
wait = WebDriverWait(driver, 600)
message = driver.find_elements_by_xpath('//*[#id="main"]/footer/div[1]/div[2]/div/div[2]')[0]
message.send_keys(":heart:")
However, this does not work and sends a string ':heart:'.
Could you please suggest how to do it correctly?
Well,
Here is a workaround! Hope it works!
text_element = driver_trader.find_element_by_xpath('xpath')
text = '⚪📢😆'
driver.execute_script("arguments[0].innerHTML = '{}'".format(text),text_element)
text_element .send_keys('.')
text_element .send_keys(Keys.BACKSPACE)
Here is a tricky way. we can take help of JavaScript and then driver.execute_script that JS code. You can use this function to do that:
from selenium import webdriver
from selenium.webdriver.common.by import By
import chromedriver_autoinstaller
chromedriver_autoinstaller.install()
driver = webdriver.Chrome()
def paste_content(driver, el, content):
driver.execute_script(
f'''
const text = `{content}`;
const dataTransfer = new DataTransfer();
dataTransfer.setData('text', text);
const event = new ClipboardEvent('paste', {{
clipboardData: dataTransfer,
bubbles: true
}});
arguments[0].dispatchEvent(event)
''',
el)
# Go to a page
driver.get('https://some-random-site-as-you-wish.com')
# Find the input box
input_el = driver.find_element(By.XPATH, '//some-xpath')
msg = 'Done! 😈 💯'
paste_content(driver, input_el, msg)
You can not do it directly. You need to do this via javascript.
Once Javascript has been formatted properly, you need to notify listeners.
Before that, you need to find the unicode of any emoji you want to use.
To get codepoint of any emoji, this website can be used:
https://emojipedia.org/
Search for any emoji and at the bottom of the page, there will be the codepoint for it.
To convert codepoint to unicode for javascript, use following website:
https://r12a.github.io/app-conversion/
Type the codepoint and copy the value in javascript box of it.
Once, you have it, use JavaScript as follows:
JS_ADD_TEXT_TO_INPUT = """
var elm = arguments[0], txt = arguments[1];
elm.value += txt;
elm.dispatchEvent(new Event('change'));
"""
elem = driver.find_element_by_id('<Id of your webelement>')
text = u'\u2764'
driver.execute_script(JS_ADD_TEXT_TO_INPUT, elem, text)
2764 is unicode for heart emoji.
Hope this helps for any kind of emoticons you want to insert to your whatsapp!
Edit: For more complex emoticons:
You need to add multiple unicodes like
Emoji for family : 👪
\uD83D\uDC6A
guys.
I found a really simple but powerfull way to add emoji to whatsApp using Selenium
Message_box.send_keys(':emoji' u'\ue007') # You just have to enter the code cording to the next page
https://gist.github.com/hkan/264423ab0ee720efb55e05a0f5f90887
Copy the emoji to clipboard and paste in the input element will work too.
mch22, men your trick is awesome! thank you very much.
just in case someone is wondering how to do a line break inside the text, you can use labels within the text like this:
text = '⚪<br>📢<br>😆'
punctures perfect for my whatsapp bot!