How to make sure the last message sent in WhatsApp python bot - python-3.x

I use the code I wrote to send a message on WhatsApp to several contacts, but before all the messages are sent, Chrome is closed and some messages are not sent. How can I be sure that the message I sent was sent?
(This is not a problem in the program) The problem is the low speed of the Internet and you have to wait a while for the message to be sent
from bs4 import BeautifulSoup
from selenium.webdriver.support import expected_conditions as EC
from time import sleep
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
import os
class WhatsApp:
def __init__(self) -> None:
user = os.getlogin()
options = webdriver.ChromeOptions()
# options.headless = True
options.add_argument('--profile-directory=Default')
options.add_argument(
f'--user-data-dir=C:\\Users\\{user}\\AppData\\Local\\Google\\Chrome\\User Data')
PATH = "chromedriver_win32\chromedriver.exe"
self.driver = webdriver.Chrome(
executable_path=PATH, chrome_options=options)
self.driver.set_window_position(0, 0)
self.driver.set_window_size(0, 0)
self.driver.get("https://web.whatsapp.com")
WebDriverWait(self.driver, 5000).until(
EC.presence_of_element_located(
(By.XPATH, '//*[#id="side"]/header/div[2]/div/span/div[2]/div'))
)
def send_msg(self, phone: str, msg: str):
search_btn = self.driver.find_element_by_xpath(
'//*[#id="side"]/header/div[2]/div/span/div[2]/div')
search_btn.send_keys(Keys.ENTER)
input_search = self.driver.find_element_by_xpath(
'/html/body/div[1]/div/div/div[2]/div[1]/span/div/span/div/div[1]/div/label/div/div[2]')
input_search.send_keys(phone, Keys.ENTER)
try:
sleep(1)
self.driver.find_element_by_xpath(
"/html/body/div[1]/div/div/div[4]/div/footer/div[1]/div/span[2]/div/div[2]/div[1]/div/div[2]").send_keys(
msg, Keys.ENTER)
except Exception as e:
pass
# showMessageBox.contacte_not_found(showMessageBox)
def check_is_sended(self, phone: str, msg: str):
pass
#some code i need to check message sended or not
def END(self):
sleep(3)
self.driver.close()
app = WhatsApp()
phone = "+98xxxxxxxx87"
message = "test"
app.send_msg(phone , message)
app.END()
so I do not want to use sleep for long time im just want to find best way to make time short for runing program any id?

when selenium clicks "send msg button", a new div will be created in html that indicates that you sent a msg. so, make selenium wait until it appears.
then make selenium also wait for the verification icon that indicates that the msg has been sent successfully to the Whatsapp server.
Q: How do I get the new message ?
A: you can wait until the chat-room html-div contains the msg you sent.
from selenium.webdriver.support import expected_conditions as EC
locator = (By.ID, 'someid') #modify this according to your case
your_new_msg = 'blabla bla' #modify this according to your case
wait.until(EC.text_to_be_present_in_element(locator, your_new_msg))
but this short solution may lead to bug because the msg may be existing within another old msg in the chat-room div. so, selenium will think that it is the intended msg then exit the wait by mistake.
so, the solution for this may be hard for you if you are a new developer.
you need to make a channel between Python and Javascript to pass the data between them
then you create an Event Listener in JS to watch the chat-room changes (eg: you can override the (chat-room-div).appendChild method. then you get the new-msg html element in your JS method before it is shown on html)
you then can send a msg from JS to python to tell him that the new-msg div has appeared and the verification icon also appeared
then python will exit its waiting state. then continue executing the next code
_____
this is just the idea. the implementation of it is up to you.

Related

I'm writing a code where I can enter Instagram and get the follower list

Hello ı'm a beginner coder
I want to login to instagram using selenium and get my follower list but my code But the code I wrote does not give any error or output.
from selenium import webdriver
import time
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
class İnstagram:
def __init__(self,name,password):
self.browser = webdriver.Firefox()
self.username = username
self.password = password
def signIn(self):
self.browser.get("https://www.instagram.com")
time.sleep(1)
name = self.browser.find_element(By.XPATH,"//*[#id='loginForm']/div[1]/div[1]/div/label/input").send_keys(self.username)
psw = self.browser.find_element(By.XPATH,"//*[#id='loginForm']/div[1]/div[2]/div/label/input").send_keys(self.password)
self.browser.find_element(By.XPATH,"//*[#id='loginForm']/div[1]/div[3]").click()
time.sleep(7)
def getFollowers(self):
self.browser.get("https://www.instagram.com/emirhaninmalikanesi/followers/")
followers = self.browser.find_elements(By.CSS_SELECTOR,"._ab8w._ab94._ab99._ab9h._ab9m._ab9o._abcm")
for user in followers:
name = user.find_element(By.CSS_SELECTOR,".x1i10hfl.xjbqb8w.x6umtig.x1b1mbwd.xaqea5y.xav7gou.x9f619.x1ypdohk.xt0psk2.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x16tdsg8.x1hl2dhg.xggy1nq.x1a2a7pz.notranslate._a6hd").get_attribute("href")
print(name)
instagram = İnstagram(username,password)
instagram.signIn()
instagram.getFollowers()
Your code has two flaws
Before login you have to close the cookies dialog, otherwise the code raises ElementClickInterceptedException when trying to click on "Log in".
No use of selenium built-in timeout methods (driver.implicitly_wait or WebDriverWait) to wait for an element to be found. This causes followers to be an empty list.
Corrected code
driver.implicitly_wait(9) # driver waits up to 9 seconds for an element to be found
driver.find_element(By.XPATH,"//div[#role='dialog']/div/button[contains(.,'cookie')]").click()
driver.find_element(By.XPATH,"//*[#id='loginForm']/div[1]/div[1]/div/label/input").send_keys(username)
driver.find_element(By.XPATH,"//*[#id='loginForm']/div[1]/div[2]/div/label/input").send_keys(password)
driver.find_element(By.XPATH,"//*[#id='loginForm']/div[1]/div[3]").click()
driver.get("https://www.instagram.com/emirhaninmalikanesi/followers/")
followers = driver.find_elements(By.CSS_SELECTOR,"._ab8w._ab94._ab99._ab9h._ab9m._ab9o._abcm")
for user in followers:
name = user.find_element(By.CSS_SELECTOR,".x1i10hfl.xjbqb8w.x6umtig.x1b1mbwd.xaqea5y.xav7gou.x9f619.x1ypdohk.xt0psk2.xe8uvvx.xdj266r.x11i5rnm.xat24cr.x1mh8g0r.xexx8yu.x4uap5.x18d9i69.xkhd6sd.x16tdsg8.x1hl2dhg.xggy1nq.x1a2a7pz.notranslate._a6hd").get_attribute("href")
print(name)
As a final consideration, notice that you can avoid the login process by loading in selenium a user profile where you are already logged in. For more info look here https://stackoverflow.com/a/75434260/8157304

This website prevent me from signing in, what should I do

I am having error when I try to sendkeys(Keys.ENTER) if I am using python to login this blibli website. But when I try to login normally from chrome browser, I can login normally without this error.
I can input the username and password with selenium python, but then it just ignores the sendkeys(Keys.Enter) command. I have tried adding the login_button.click() command, but the selenium seems to ignore the click() command too. Then, when I tried to click the login button manually, I got an error: "Yah, ada eror nih. Coba lagi, ya." Meaning: "There is an error. Please try again, ok.".
It seems like the website can detect if I am using automated software, thus prevent me from logging into the website, eventhough it is my own account. I have attached the error screenshot. The error prevents me from clicking enter or clicking the blue login button ("Masuk").
Can anybody solve this? Thank you.
The process is complete, because I got this response:
Process finished with exit code 0
This is my code:
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver import ActionChains
from time import sleep
import os
CHROME_DRIVER_PATH = "C:\Development\chromedriver_win32\chromedriver.exe"
URL = "https://www.blibli.com/login"
EMAIL = os.environ['EMAIL']
BLIBLI_PASSWORD = os.environ["BLIBLI_PASSWORD"]
class Blibli:
def __init__(self):
self.driver = webdriver.Chrome(executable_path=CHROME_DRIVER_PATH)
def login(self):
self.driver.get(URL)
sleep(3)
username = self.driver.find_element_by_class_name("login__username")
username.send_keys(EMAIL)
# actions = ActionChains(self.driver)
# actions.move_to_element(username).send_keys(EMAIL)
password = self.driver.find_element_by_css_selector('input[type="password"]')
password.send_keys(BLIBLI_PASSWORD, Keys.ENTER)
login_button = self.driver.find_element_by_class_name("blu-btn")
login_button.click()
def get_data(self):
pass
bot = Blibli()
bot.login()
bot.get_data()

Scrape Product Image with BeautifulSoup (Error)

I need your help. I'm working on a telegram bot which sends me all the sales from amazon.
It works well but this function doesn't work properly. I have always the same error that, however, blocks the script
imgs_str = img_div.img.get('data-a-dynamic-image') # a string in Json format
AttributeError: 'NoneType' object has no attribute 'img'
def take_image(soup):
img_div = soup.find(id="imgTagWrapperId")
imgs_str = img_div.img.get('data-a-dynamic-image') # a string in Json format
# convert to a dictionary
imgs_dict = json.loads(imgs_str)
#each key in the dictionary is a link of an image, and the value shows the size (print all the dictionay to inspect)
num_element = 0
first_link = list(imgs_dict.keys())[num_element]
return first_link
I still don't understand how to solve this issue.
Thanks for All!
From the looks of the error, soup.find didn't work.
Have you tried using images = soup.findAll("img",{"id":"imgTagWrapperId"})
This will return a list
Images are not inserted in HTML Page they are linked to it so you need wait until uploaded. Here i will give you two options;
1-) (not recommend cause there may be a margin of error) simply; you can wait until the image is loaded(for this you can use "time.sleep()"
2-)(recommend) I would rather use Selenium Web Driver. You also have to wait when you use selenium, but the good thing is that selenium has a unique function for this job.
I will show how make it with selenium;
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
browser = webdriver.Chrome()
browser.get("url")
delay = 3 # seconds
try:
myElem = WebDriverWait(browser, delay).until(EC.presence_of_element_located((By.ID, 'imgTagWrapperId')))# I used what do you want find
print ("Page is ready!")
except TimeoutException:
print ("Loading took too much time!")
More Documention
Code example for way 1
Q/A for way 2

How do i use “wait until” element before certain page is displayed? (using python 3.7)

First of all, i am a newbie in testing app using appium (python 3.7). Here, i am testing an app where i have to wait right after login process is completed. I have done this using implicit wait. But now, to make the testing process more dynamic i want to wait until the next page is displayed.
Note: I have seen and tried several issues of this forum but could not help myself.
Here's the code:
from appium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
desired_cap = {
"platformName": "Android",
"deviceName": "QDG9X18426W11577",
"newCommandTimeout": "240",
"app": "C:\\Users\\tahmina\\Downloads\\test-v3.10.apk",
"appPackage": "com.cloudapper.android",
"appActivity": "com.cloudapper.android.SplashActivity"
}
#Making connection with Appium server
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_cap)
#Here i have used implicit wait to load the login page
driver.implicitly_wait(20)
#Login to the app
search_element = driver.find_element_by_id('Username').send_keys('test#yandex.com')
search_element = driver.find_element_by_id('Password').send_keys('1155qQQ')
search_element = driver.find_element_by_xpath(
'/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View[2]/android.widget.Button').click()
wait = WebDriverWait(driver, 10)
#Waiting until the next process comes up
if webdriver.wait.until(driver.find_element_by_id('com.cloudapper.android:id/item_bg').is_displayed()):
print('Run the next process')
elif webdriver.wait.until(not driver.find_element_by_id('com.cloudapper.android:id/item_bg')):
print('Something went wrong!')
#Searching employee by using ID
search_element = driver.find_element_by_id('com.cloudapper.android:id/edtSearch').send_keys('1018')
driver.execute_script('mobile:performEditorAction', {'action': 'search'})
Guide me if anyone of you have any solution about it.
With Python, you can use WebDriverWait and ExpectedConditions to solve your problem.
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
#Login to the app
search_element = driver.find_element_by_id('Username').send_keys('test#yandex.com')
search_element = driver.find_element_by_id('Password').send_keys('1155qQQ')
search_element = driver.find_element_by_xpath(
'/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View[2]/android.widget.Button').click()
# Waiting until the next process comes up
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "com.cloudapper.android:id/item_bg")))
If you want to implement the WebDriverWait in a try / except block, you can handle the case where your desired element does not appear on the page:
from selenium.common.exceptions import TimeoutException
# Waiting until the next process comes up
try:
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "com.cloudapper.android:id/item_bg")))
except TimeoutException as ex:
# handle the exception here
print("Exception has been thrown. " + str(ex))
Because you are using the explicit wait.until keyword, you should not set driver Implicit wait. It is bad practice to set both implicit and explicit wait in your automation tests, and can yield unexpected wait times.
On another note -- I noticed you are using explicit XPath notation in some of your selectors. XPath is a great method for selecting elements, but using explicit selectors as such makes your code very brittle. I recommend using relative selectors instead. You can replace this:
search_element = driver.find_element_by_xpath(
'/hierarchy/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout/android.widget.LinearLayout/android.widget.FrameLayout[2]/android.webkit.WebView/android.webkit.WebView/android.view.View/android.view.View[2]/android.widget.Button').click()
with this:
search_element = driver.find_element_by_xpath('//android.widget.Button').click()
You may have to query on additional attributes such as text --
search_element = driver.find_element_by_xpath('//android.widget.Button[#text='Log in']').click()
Overall, this method is much more efficient.
Have you tried something like this:
import time
time.sleep(0.5)
This is for anyone who face the same problem:
Import WebDriverWait and ExpectedConditions
Use this as explicit wait in your code
WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.ID, "com.cloudapper.android:id/item_bg")))

Automating Dropdown Menu, Select and Send Keys

I am trying to automate some functions for a webpage. Specifically my goal is to automate within the "Download posts by username" section of https://vurku.com/
Whereby I pass username info to the "username" section, click and select images from the "post type" section, and click download.
However I can not seem to pass the username keys into the username section, and am getting an error that states:
line 20, in driver_pass_username_keys
self.driver.find_element(By.XPATH, "//* [#id='collection_username']").sendkeys("guendouglas")
AttributeError: 'FirefoxWebElement' object has no attribute 'sendkeys'
I have worked through many different versions of this code, as I am new to python and selenium, but since I am rather new I am lost. This code worked when I didn't program it from an object oriented perspective. But I'm trying to practice OOP.
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
from selenium.common.exceptions import TimeoutException
class AutomateVurku:
def __init__(self,driver):
self.driver = driver
def driver_load_page(self):
self.driver.get("https://vurku.com/")
return WebDriverWait(self.driver, 10).until(EC.element_to_be_clickable((By.ID, "collection_username")))
def driver_pass_username_keys(self):
self.driver.find_element(By.XPATH, "//*[#id='collection_username']").sendkeys("guendouglas")
# def driver_select_image_dropdown(self):
if "__main__" == __name__:
driver = webdriver.Firefox(executable_path="/Users/alexandrubordei/Desktop/geckodriver")
myclass = AutomateVurku(driver)
myclass.driver_load_page()
myclass.driver_pass_username_keys()
as stated, I am receiving an error that states that FireFoxWebElement doesn't have an attribute "send keys"
I am not sure what that even means
I guess this was already answered under this question:
Here
Hope, it helps.

Resources