DEV Community

Cover image for Send Bulk WhatsApp Messages In Python | Automate WhatsApp Using Python
All About Python
All About Python

Posted on

Send Bulk WhatsApp Messages In Python | Automate WhatsApp Using Python

What’s up pythoneers, I’m back again with another blog on my channel All About Python. If you have been following my channel, you would know that I have started a python automation playlist where I attempt to automate various well-known apps and APIs using python. And three such blog have been performing really well, especially the Instagram automation blog . So I decided to, this time, make a blog on automating WhatsApp messaging with python, and next, I will make a blog on automating Twitter. So
don’t forget to subscribe to my channel and click on the bell icon so that you are notified whenever I upload a new blog

This blog will focus on creating a python script that will read the phone numbers, names, and messages from excel and then send bulk WhatsApp messages to the respective phone numbers. One catch here is that the phone number should be saved on the device which is being used to send the WhatsApp message.

In this blog , I am gonna discuss, about

  1. WhatsApp Web and how this script uses it
  2. Function wise analysis of the script
  3. Quick demo explaining the working of the script
  4. An alternative way to create the script.
  5. Some ideas for modifications and improvements within the script

Let’s start with WhatsApp Web:

WhatsApp Web

Send Bulk WhatsApp Messages In Python - WhatsApp Web
WhatsApp Web

WhatsApp Web is a feature of WhatsApp that lets you operate your
WhatsApp from your laptop or desktop browser. The steps to use WhatsApp web are pretty simple, just open a chrome browser within your computer and open site web.whatsapp.com, next scan the appearing QR code using your phone, and your WhatsApp will appear on the chrome browser. Here you can message anyone or any group or can see WhatsApp status.

This script uses the selenium library to automate the browser and send bulk messages to multiple contacts within WhatsApp.

With the basic working of the script understood, let’s move on to
functional-wise analysis of the script.

import art, time, os, platform
from colorama import init, Fore
from termcolor import colored
import pandas as pd
import datetime
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
Enter fullscreen mode Exit fullscreen mode

The script starts by importing all the required modules. 

  • The art module is used to create and display ASCII art for the script. If you wanna know how it works, you can check out this blog.
  • Time is used to halt program execution for some seconds using time.sleep()
  • OS is used to run operating system commands within the script.
  • The platform module is used to identify the operating system.

Together, os and platform are used to clear the screen, as you can see
here.

  • Colorama and termcolor are used to display colored console output of the script. If you wanna know more about them, you can check out this blog.
  • Pandas is used to read data from the excel file.
  • Datetime is used to find the current date and time.
  • And finally, we have selenium. All these import statements you see here are just importing
  • Required classes and functions from selenium.
FILE_LOC = "data.xlsx"
SRNO = 'SRNO'
NAME = 'Name'
PHONENUMBER = 'Phone Number'
MESSAGE = 'Message'
REPLACENAME = '{{name}}'
URL = 'https://web.whatsapp.com/'
WAITER_ELEMENT = "landing-title _3-XoE"
PHONE_NUMER_INPUT = "//*[@id='side']/div[1]/div/label/div/div[2]"
PERSON_DIV = "//*[@id='pane-side']/div[1]/div/div/div[1]/div/div/div[1]/div/div/img"
MESSAGE_INPUT = "//*[@id='main']/footer/div[1]/div[2]/div/div[1]/div/div[2]"
SEND_BUTTON = "//*[@id='main']/footer/div[1]/div[2]/div/div[2]/button"
Enter fullscreen mode Exit fullscreen mode

Next, we have all the constants used within the script, including the URL, excel field names, button, and textbox xpaths, etc. Just a quick idea, xpaths are basically like search filters that are used to identify a certain element or a group of elements within an HTML page.

driver = webdriver.Chrome('chromedriver.exe')
driver.implicitly_wait(10)
waiter = WebDriverWait(driver, 10)
data = []
Enter fullscreen mode Exit fullscreen mode

Next, we have started and configured the driver and waiter of our
script.

def printData(message, type):
    if type == 'INFO':
        print('[' + colored(datetime.datetime.now().strftime('%H:%M:%S'), 'cyan') + '][' + colored('INFO', 'green') +  '] ' + message)
    elif type == 'WARNING':
        print('[' + colored(datetime.datetime.now().strftime('%H:%M:%S'), 'cyan') + '][' + colored('WARNING', 'yellow') +  '] ' + message)
    elif type == 'ERROR':
        print('[' + colored(datetime.datetime.now().strftime('%H:%M:%S'), 'cyan') + '][' + colored('ERROR', 'red') +  '] ' + message)
Enter fullscreen mode Exit fullscreen mode

Now we have the first function of our script, the printData function.

This function requires two arguments, message, and type. This function is used to print colored data on the console, either informational, warning or error.The function simply checks what is the type passed onto it and accordingly prints the message on the console.

def read_data_from_excel():
    try:
        df = pd.read_excel(FILE_LOC)
        printData("Retrieving data from excel", 'INFO')
    except:
        printData("Excel 'data.xlsx' not found", 'ERROR')
    printData("Found {0} messages to be send".format(len(df.index)), 'INFO')
    for i in df.index:
        if '+' not in str(df[PHONENUMBER][i]):
            number = '+91' + str(df[PHONENUMBER][i])
        else:
            number = str(df[PHONENUMBER][i])
        output = {
            'SrNo': df[SRNO][i],
            'Name': df[NAME][i],
            'PhoneNumber': number,
            'Message': df[MESSAGE][i].replace(REPLACENAME, df[NAME][i])
        }
        data.append(output)
Enter fullscreen mode Exit fullscreen mode

Next, we have the read_data_from_excel() function that reads all the messages to be sent from the data.xlsx file. The function uses the pandas' library to read the data from excel and store the excel entries in a data list within the script.

def send_whatsapp_message():
    global driver
    driver.get(URL)
    printData("Loading site...", 'INFO')
    waiter.until(EC.title_is("WhatsApp"))
    printData("Site loaded successfully...", 'INFO')
    printData("Waiting for user to log in using WhatsApp Web", 'INFO')
    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:
                printData("Waiting for user to log in...", 'WARNING')
        except:
            printData("Logged in to WhatsApp", 'INFO')
            break

    for entry in data:
        driver.find_element_by_xpath(PHONE_NUMER_INPUT).send_keys(str(entry['PhoneNumber']))
        time.sleep(5)
        driver.find_element_by_xpath(PHONE_NUMER_INPUT).send_keys(Keys.ENTER)
        time.sleep(5)
        driver.find_element_by_xpath(MESSAGE_INPUT).send_keys(str(entry['Message']))
        time.sleep(5)
        driver.find_element_by_xpath(SEND_BUTTON).click()
        time.sleep(5)
        printData("Successfully send message to {0}, name: {1}".format(str(entry['PhoneNumber']), str(entry['Name'])), 'INFO')
Enter fullscreen mode Exit fullscreen mode

Next, we have the most important function of the script, which is the send_whatsapp_message() function. This function is responsible for reading contacts from the data list and one-by-one send WhatsApp messages to each one of them. 

The function starts by loading the WhatsApp website and waiting for it to load. Once the site is loaded, the script waits for the user to scan the QR code and log in to the site. Once the user is logged in, the script searches for each contact, opens its chat, types the message, and sends it.

if __name__ == '__main__':
    # Initialize colorama
    init()

    # Clear the screen
    if platform.system() == 'Windows':
        os.system('cls')
    else:
        os.system('clear')

    # Display ASCII art
    print(art.text2art("WhatsApp Python"))
    print(Fore.CYAN + "\nCreated By:" + Fore.RESET + " Vishesh Dvivedi [All About Python]\n")
    print(Fore.YELLOW + "GitHub: " + Fore.RESET + "   visheshdvivedi")
    print(Fore.YELLOW + "Youtube:" + Fore.RESET + "   All About Python")
    print(Fore.YELLOW + "Instagram:" + Fore.RESET + " @itsallaboutpython")
    print(Fore.YELLOW + "Blog Site:" + Fore.RESET + " itsallaboutpython.blogspot.com\n")


    # Read data from 'data.xlsx' file
    read_data_from_excel()

    # Send whatsapp message 
    send_whatsapp_message()

    # Close chromedriver
    driver.close()
Enter fullscreen mode Exit fullscreen mode

And finally, we have the main function. In case you are unclear with the use of if __name__ == ‘__main__’, then you can check out a blog on my channel dedicated to this topic.

Within the main function, first, init() is used to initialize Colorama. Next, I have used a code snippet to execute an OS command to clear the screen, based on the operating system used. Next, the art module is used to display the ASCII are for the script, and below that, you will find contact information about me, in case you want to contact me.

And finally, we call the read_data_from_excel() and
send_whatsapp_message() function which performs the rest of the
functions, as we discussed before. And then we end the script by closing the driver.

That’s all there is in this script. Here is the full code.

import art, time, os, platform
from colorama import init, Fore
from termcolor import colored
import pandas as pd
import datetime
from selenium import webdriver
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains

FILE_LOC = "data.xlsx"
SRNO = 'SRNO'
NAME = 'Name'
PHONENUMBER = 'Phone Number'
MESSAGE = 'Message'
REPLACENAME = '{{name}}'
URL = 'https://web.whatsapp.com/'
WAITER_ELEMENT = "landing-title _3-XoE"
PHONE_NUMER_INPUT = "//*[@id='side']/div[1]/div/label/div/div[2]"
PERSON_DIV = "//*[@id='pane-side']/div[1]/div/div/div[1]/div/div/div[1]/div/div/img"
MESSAGE_INPUT = "//*[@id='main']/footer/div[1]/div[2]/div/div[1]/div/div[2]"
SEND_BUTTON = "//*[@id='main']/footer/div[1]/div[2]/div/div[2]/button"

driver = webdriver.Chrome('chromedriver.exe')
driver.implicitly_wait(10)
waiter = WebDriverWait(driver, 10)
data = []

def printData(message, type):
    if type == 'INFO':
        print('[' + colored(datetime.datetime.now().strftime('%H:%M:%S'), 'cyan') + '][' + colored('INFO', 'green') +  '] ' + message)
    elif type == 'WARNING':
        print('[' + colored(datetime.datetime.now().strftime('%H:%M:%S'), 'cyan') + '][' + colored('WARNING', 'yellow') +  '] ' + message)
    elif type == 'ERROR':
        print('[' + colored(datetime.datetime.now().strftime('%H:%M:%S'), 'cyan') + '][' + colored('ERROR', 'red') +  '] ' + message)

def read_data_from_excel():
    try:
        df = pd.read_excel(FILE_LOC)
        printData("Retrieving data from excel", 'INFO')
    except:
        printData("Excel 'data.xlsx' not found", 'ERROR')
    printData("Found {0} messages to be send".format(len(df.index)), 'INFO')
    for i in df.index:
        if '+' not in str(df[PHONENUMBER][i]):
            number = '+91' + str(df[PHONENUMBER][i])
        else:
            number = str(df[PHONENUMBER][i])
        output = {
            'SrNo': df[SRNO][i],
            'Name': df[NAME][i],
            'PhoneNumber': number,
            'Message': df[MESSAGE][i].replace(REPLACENAME, df[NAME][i])
        }
        data.append(output)

def send_whatsapp_message():
    global driver
    driver.get(URL)
    printData("Loading site...", 'INFO')
    waiter.until(EC.title_is("WhatsApp"))
    printData("Site loaded successfully...", 'INFO')
    printData("Waiting for user to log in using WhatsApp Web", 'INFO')
    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:
                printData("Waiting for user to log in...", 'WARNING')
        except:
            printData("Logged in to WhatsApp", 'INFO')
            break

    for entry in data:
        driver.find_element_by_xpath(PHONE_NUMER_INPUT).send_keys(str(entry['PhoneNumber']))
        time.sleep(5)
        driver.find_element_by_xpath(PHONE_NUMER_INPUT).send_keys(Keys.ENTER)
        time.sleep(5)
        driver.find_element_by_xpath(MESSAGE_INPUT).send_keys(str(entry['Message']))
        time.sleep(5)
        driver.find_element_by_xpath(SEND_BUTTON).click()
        time.sleep(5)
        printData("Successfully send message to {0}, name: {1}".format(str(entry['PhoneNumber']), str(entry['Name'])), 'INFO')

if __name__ == '__main__':
    # Initialize colorama
    init()

    # Clear the screen
    if platform.system() == 'Windows':
        os.system('cls')
    else:
        os.system('clear')

    # Display ASCII art
    print(art.text2art("WhatsApp Python"))
    print(Fore.CYAN + "\nCreated By:" + Fore.RESET + " Vishesh Dvivedi [All About Python]\n")
    print(Fore.YELLOW + "GitHub: " + Fore.RESET + "   visheshdvivedi")
    print(Fore.YELLOW + "Youtube:" + Fore.RESET + "   All About Python")
    print(Fore.YELLOW + "Instagram:" + Fore.RESET + " @itsallaboutpython")
    print(Fore.YELLOW + "Blog Site:" + Fore.RESET + " itsallaboutpython.blogspot.com\n")


    # Read data from 'data.xlsx' file
    read_data_from_excel()

    # Send whatsapp message 
    send_whatsapp_message()

    # Close chromedriver
    driver.close()
Enter fullscreen mode Exit fullscreen mode

Let’s go through a quick demo to see how it works.

WhatsApp Automation Python
WhatsApp Automation Python

This is how the script looks like when it is executed. I have the chrome browser right here and the web.whatsapp.com site is opened right here. Now I will scan the QR code using WhatsApp and my WhatsApp will appear in front of my screen.

After this, the script will, one by one, search for contacts from all the contacts, open their chat, and then it will automatically message them. If the message is of multiple lines, then a message will be sent for each line.

I hope this cleared your doubts about this script. In case you still have any doubts left, you can mention it down in the comments below.

All of this code may be a bit confusing for some of you, and you may wonder whether there is an alternative and easy way to make this code. There is!

pywhatkit
pywhatkit

There is a module by the name pywhatkit, which contains a method that allows you to send custom WhatsApp messages. If you guys want, I will make a separate blog explaining pywhatkit to you all.

Now comes the last topic of this blog , Ideas for modifications and improvements in the blog . I had created this script just to explain to you all how you can create this script. However, there are still a ton of modifications and improvements that can be done within the script.

For example, you can add a time system to it which will allow you to send WhatsApp messages at a specific time and day. For that, you’ll have to add a while loop before calling the send_whatsapp_message. The loop will check after every minute the current time. If it matches the time to send the WhatsApp message, the loop will break and the message will be sent.

Similarly, you can create a constant for wait time and that constant can be used to find out how much wait should be done while sending the message, as WhatsApp web may block this python script in some cases.

That’s all in this blog guys, hope you liked my blog . If you did, don’t forget to subscribe to my channel to check for various other automation scripts that I have created for Instagram and YouTube.  

With this, it's time for me to go, this is Vishesh Dvivedi, signing off.

Latest comments (3)

Collapse
 
kalebu profile image
Jordan Kalebu

Great one, I also recently made a python library which abstract selenium and provide easy and intuitive interface plus advanced control over the WhatsApp Web, you might wanna have a look at it github.com/Kalebu/alright

Collapse
 
emil_jung profile image
Emil Jung 🇳🇦🇿🇦🇳🇱🇧🇪🇶🇦🇷🇼

NoSuchElementException: no such element: Unable to locate element: {"method":"xpath","selector":"//*[@id='main']/footer/div[1]/div[2]/div/div[1]/div/div[2]"}
(Session info: chrome=101.0.4951.54)

Collapse
 
emil_jung profile image
Emil Jung 🇳🇦🇿🇦🇳🇱🇧🇪🇶🇦🇷🇼

Help me. How should the data.xlsx look like in terms og columns?