LinkedIn is a purely professional networking and employment-oriented website. It is a platform where the world’s employees and employers can meet and interact with each other. So when it comes to a special day like a birthday, then wishing without forgetting is a must to make stronger connections. Now you don’t need to worry about wishing all of them personally, you just need to use this script and run it to wish them together. Very fast and without much hustle. So let’s make this script!
What is selenium?
Selenium is one of the free of the automated testing frameworks used to automate web browsers. We can use selenium with multiple languages like Java, Python, Ruby, C#, etc. Selenium is more than just a single tool; it’s a collection of tools, each of which caters to a certain organization’s Selenium QA testing requirements. Selenium Integrated Development Environment(IDE), Selenium Remote Control (RC), WebDriver, Selenium grid are tools of selenium.
To automate the browser here, we will use the selenium WebDriver tool. Selenium WebDriver is a web framework that permits you to execute cross-browser tests. This tool is used for automating web-based application testing to verify that it performs expectedly.
Installation and getting started
When starting a new project in python, the ideal approach is to create a new environment and work in it. This is helpful because it separates other projects and their dependencies in distinct places, which allows for easy deployment if needed, and clear package-managing.
python -m venv env_name
After running this in cmd, the folder will be created with the name of your environment name. After creating the environment, activate it and now we will install our required dependencies for our project.
Install Selenium libraries for Python using pip. More info on installation can be found here.
pip install selenium
We have to install a web driver that Selenium will utilize to use the browser. We can use any browser, but here, we will use Chrome-Driver for Google Chrome/Chromium. You can download the web driver here.
For creating a web application, we have used Flask. For installing Flask in your virtual environment, use the command below.
pip install -U Flask
We have to install some other packages for this project. Create a requirements.txt file, add this into this file and run the below command. This will install all the packages which are needed in this project.
pip install -r requirements.txt
1. Creating .env file
To store the email ID and passwords, we will create a .env file and get the login credentials from the .env file.
Make sure that the format of the .env is exactly same as below. Here the first two env variables i.e. EMAIL & PASSWORD are used for LinkedIn Login, and the last two i.e. SENDER_EMAIL & SENDER_PASSWORD are used for Email authentication, which is used in exceptionMail.py file.
2. Creating a python file for sending mail.
If any exception occurs, or if a birthday is successfully wished, or if there is no birthday today, we will send a mail to the user. To do so, use the code below.
import smtplib, ssl
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import time
import os
# Defined sender email credentials in the .env file and accessing using os methods
sender_email = os.getenv("SENDER_EMAIL")
password = os.getenv("SENDER_PASSWORD")
def sendMail(receiver_email, bodyMessage):
message = MIMEMultipart("alternative")
message["Subject"] = "RE: Your automatic birthday wisher"
message["From"] = sender_email
message["To"] = receiver_email
# # Turn these into plain/html MIMEText objects
part1 = MIMEText(bodyMessage, "plain")
# Add HTML/plain-text parts to MIMEMultipart message
# The email client will try to render the last part first
message.attach(part1)
# Create secure connection with server and send email
context = ssl.create_default_context()
try:
with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
server.login(sender_email, password)
time.sleep(10)
server.sendmail(
sender_email, receiver_email, message.as_string()
)
time.sleep(5)
return "Mail sent"
except Exception as e:
print(e)
return "Mail could not sent Exception is : {}".format(e)
3. Get the required terms using Inspect elements
By using the “inspect element”, we can detect that the email text box element contains the ID ‘username’. The password’s id is similar, with its id being ‘password’. We can utilize the ‘find_element_by_id’ function to get those elements in the HTML. After obtaining the text box elements, we can call the ‘send_keys(string)’ method on those boxes with a specified string.
4. Creating a Function for Login and wishing happy birthday.
Create a python file named linkedInBirthday.py and copy the below code in that file.
We will import the necessary Modules and Libraries for the python file.
import time
import csv
from bs4 import BeautifulSoup
from datetime import date
from exceptionMail import sendMail
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
import pandas as pd
from selenium.webdriver.common.action_chains import ActionChains
import os
Then, we will use the username and password from the .env file.
# Defined sender email credentials in the .env file and accessing using os methods
usr = os.getenv("EMAIL")
pwd = os.getenv("PASSWORD")
First, we will go to the connection page and scrape all the connection’s details, profile links, and store it in the CSV file.
When the total connection is the same as in the CSV file, then we won’t scrape the user details, while running the script again.
We will iterate through all these pages and scrape all the connection details.
After scraping all user details, we will use those profile links and scrape the birthdate of each connection from the contact info section.
Follow the code given below.
#Declare the below variables
header = ['name', 'Link', 'image', 'Bithday']
data = []
index = []
message = ''
connList = {}
birthdayList = {}
last_page = 0
def runScript():
driver = webdriver.Chrome()
driver.get('https://www.linkedin.com/login')
print("Opened Linkedin")
username_box = driver.find_element_by_id('username')
username_box.send_keys(usr)
print("Email Id entered")
time.sleep(1)
password_box = driver.find_element_by_id('password')
password_box.send_keys(pwd)
print("Password entered")
login_box = driver.find_element_by_xpath(
'//*[@id="organic-div"]/form/div[3]/button')
login_box.click()
time.sleep(10)
print('logged in')
time.sleep(3)
driver.get(
"https://www.linkedin.com/search/results/people/?network=%5B%22F%22%5D&origin=FACETED_SEARCH&sid=RUx")
time.sleep(4)
# Scrap the list of profiles
def get_profile_of_a_page():
position = 0
birthdayslist = driver.find_elements_by_class_name(
'entity-result__item')
for b in birthdayslist:
profileLink = b.find_element_by_tag_name("a")
name = profileLink.text
linkk = profileLink.get_attribute("href")
try:
imageTagFinder = b.find_element_by_tag_name("img")
image = imageTagFinder.get_attribute("src")
except:
image = 'https://www.pngarea.com/pngm/90/6980003_profile-icon-png-facebook-default-profile-picture-girl.png'
connList[position] = {'link': linkk, 'name': name, 'image': image}
position = position + 1
# Scrolling a full-page
def scroll_till_end():
try:
html = driver.find_element_by_tag_name('html')
html.send_keys(Keys.END)
except Exception as e:
print(str(e))
# moving to next page
def next_page():
try:
next_button = driver.find_element_by_class_name(
'artdeco-pagination__button.artdeco-pagination__button--next.artdeco-button.artdeco-button--muted.artdeco-button--icon-right.artdeco-button--1.artdeco-button--tertiary.ember-view')
driver.execute_script("arguments[0].click();", next_button)
time.sleep(4)
# break
except Exception as e:
print(e)
# Add all connection details into the CSV file
def addConnectionToCsv():
for user in connList:
driver.get(connList[user]['link'])
time.sleep(3)
driver.find_element_by_class_name(
'ember-view.link-without-visited-state.cursor-pointer.text-heading-small.inline-block.break-words').click()
time.sleep(2)
try:
birthdate = driver.find_element_by_class_name(
'pv-contact-info__contact-item.t-14.t-black.t-normal').text
time.sleep(4)
data.append([connList[user]['name'], connList[user]
['link'], connList[user]['image'], birthdate])
loopVar = loopVar + 1
# write multiple rows
except Exception as e:
print(e)
with open('linkedinProfiles.csv', 'w', encoding='UTF8', newline='') as f:
writer = csv.writer(f)
# write the header
writer.writerow(header)
writer.writerows(data)
# checks if today is somone's birthday or not
def isbirthday():
today = date.today()
# Textual month, day and year
d2 = today.strftime("%B %#d %Y")
currentDate = d2.split()
currentDate.pop()
dataOfCsv = pd.read_csv("linkedinProfiles.csv")
# converting column data to list
connectionBirthdates = dataOfCsv['Bithday'].tolist()
for birthday in range(len(connectionBirthdates)):
if connectionBirthdates[birthday].split() == currentDate:
index.append(birthday)
# Count data in CSV
def dataInCSV():
try:
dataInCsv = pd.read_csv("linkedinProfiles.csv")
except Exception as e:
print(e)
return 0
listOfData = dataInCsv['Bithday'].tolist()
print("totalCSVdata : ", len(listOfData))
return len(listOfData)
# Fetch the total connection
def totalConnection():
totConnection = driver.find_element_by_class_name(
'pb2.t-black--light.t-14').text
conn = totConnection.split()
conn.pop()
print("totalConnectiondata : ", int(conn[0]))
return int(conn[0])
# Get the list whose birthday is today
def getBirthdayList():
listCount = 0
with open('linkedinProfiles.csv') as csv_file:
csv_reader = csv.reader(csv_file)
next(csv_reader)
row = list(csv_reader)
# fhandle = open('linkedinProfiles.csv')
for ind in index:
rowneeded = row[ind]
birthdayList[listCount] = {
'name': rowneeded[0], 'link': rowneeded[1], 'image': rowneeded[2], 'birthday': rowneeded[3]}
listCount = listCount + 1
def pageToScrape():
try:
response = driver.page_source
soup = BeautifulSoup(response, 'html.parser')
all_pages = soup.find_all(class_="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view")
global last_page
if len(all_pages)>0:
print("total pages:",len(all_pages))
last_page = all_pages[-1].text
print("last_page",all_pages[-1].text)
else:
print("No data")
last_page = 1
except:
print("Can't find the element")
# Check the count of connections in CSV and the actual connection count
if dataInCSV() == totalConnection():
print("Finding the bithday of connections")
isbirthday()
getBirthdayList()
else:
print("Scraping the connections details\n")
pageToScrape()
for i in range(int(last_page)):
scroll_till_end()
get_profile_of_a_page() # profile scrapping function!
scroll_till_end()
next_page()
time.sleep(4)
addConnectionToCsv()
print("Finding the bithday of connections")
isbirthday()
getBirthdayList()
print(index)
# Sends the message
def sendMessage():
global message
global index
global connList
if index != []:
message = "Birthday wished"
connListFromCSV = pd.read_csv("linkedinProfiles.csv")
BirthdayConnLinks = connListFromCSV['Link'].tolist()
for indexNumber in index:
link = BirthdayConnLinks[indexNumber]
# Logic to send Message
driver.get(link)
time.sleep(4)
msg = driver.find_element_by_link_text('Message').click()
time.sleep(3)
inbox = driver.find_element_by_class_name(
'msg-form__contenteditable.t-14.t-black--light.t-normal.flex-grow-1.full-height.notranslate')
inbox.send_keys('Happy Birthday')
time.sleep(3)
send = driver.find_element_by_class_name(
'msg-form__send-button.artdeco-button.artdeco-button--1')
ActionChains(driver).move_to_element(
send).click(send).perform()
time.sleep(3)
try:
close = driver.find_elements_by_class_name(
'msg-overlay-bubble-header__control.artdeco-button.artdeco-button--circle.artdeco-button--muted.artdeco-button--1.artdeco-button--tertiary.ember-view')
for closebut in close:
closebut.click()
except:
print("No close button found")
exp = "There is some problem sending the message, try again or contact the developer."
sendMail(receiver_email=usr, bodyMessage=exp)
time.sleep(3)
print('Message send')
else:
message = "No more birthday for today"
sendMessage()
return message, birthdayList
driver.close()
You will find the whole script here.
Now we will use this runScript() function in our flask project.
What is Flask?
Flask is a python web framework, for developing web applications.
Here, we will use Flask for running our script and Displaying user information or any other error that occurs while running the script.
The File Structure
We will create a flask app named flask_app.py. In this file, we will import the required modules and some functions of linkedInBirthday.py, add the following code in flask_app.py
from flask import Flask, render_template, redirect, session, url_for
import time
import os
from linkedInBirthday import runScript
app = Flask(__name__)
app.secret_key = os.urandom(24)
birthdayData = {}
index = []
@app.route('/')
def hello_world():
return render_template('home.html')
@app.route('/running-script')
def running_script():
data = runScript()
print(data[0])
session['messages'] = data[0]
global birthdayData
global index
birthdayData = data[1]
return redirect(url_for('.success', messages = data[0]))
@app.route('/success')
def success():
# messeges = request.args['messages']
global birthdayData
messages = session['messages']
return render_template('/success.html', messages = messages, birthday = birthdayData)
if __name__ == '__main__':
app.run(debug=True)
Now we will create two HTML files in the template folder.
The first home.html, add the following code in it. It’s the start-up page when we run the flask app.
Facebook-script
Executing the Script..............
Execute the Script
The second is success.html. This HTML template will display the status of the runScript() and print User information if there is a birthday today from your connections. Add the following code to it.
Success
Script Executed, {{ messages }}
{% for b in birthday %}
{{ birthday[b]['name'] }}
{{ birthday[b]['birthday'] }}
{% endfor %}
For a CSS file create a folder like this. –> static/styles. In styles, folder create CSS file name home.css and add following code in it.
body {
background: white;
font-family: "Poppins", sans-serif;
}
.btnn {
text-decoration: none;
outline: none;
padding: 10px 20px;
background: rgb(190, 255, 194);
color: rgb(2, 2, 2);
border: none;
border-radius: 3px;
cursor: pointer;
transition: all 0.5s;
margin: 10px auto;
width: max-content;
text-align: center;
}
.btnn:hover {
background-color: rgb(85, 255, 96);
}
.signupStyle {
display: flex;
justify-content: center;
align-content: center;
margin-top: 300px;
flex-direction: column;
}
/* For layout purpose */
.BasicLayout {
width: 1100px;
height: auto;
max-width: 75%;
padding: 30px 50px;
float: left;
margin: 0 auto;
margin-bottom: 2em;
display: flex;
flex-direction: column;
}
.outerDiv {
display: flex;
}
.profileCards {
margin-top: 25px;
display: flex;
width: 310px;
border-radius: 5px;
margin-right: 5px;
justify-content: space-around;
padding: 15px;
align-items: center;
background-color: rgb(223, 255, 225);
}
.profileImage {
width: 110px;
height: 110px;
border-radius: 50%;
}
.profileName {
font-size: 1.6em;
font-weight: 500;
color: rgb(55, 255, 68);
}
.flexDir{
display: flex;
gap: 10px;
}
.ProcessingDiv{
display: flex;
height: 100%;
}
To run the flask app
python flask_app.py
After running this script, copy the URL from the command prompt and open it into the browser. Click on the “Execute the script” button. The script will wish if there are any birthdays and will display name and birthday of user whom the birthday is wished.
That’s it!
You can also put this script to run daily using cron job and you will be wishing Birthday wishes to your LinkedIn friends daily!