LinkedIn is a purely skilled networking and employment-oriented web site. It’s a platform the place the world’s workers and employers can meet and work together with one another. So on the subject of a special occasion like a birthday, then wishing with out forgetting is a should to reinforce connections. Now you don’t want to fret about wishing all of them personally, you simply want to make use of this script and run it to want them collectively. Very quick and with out a lot hustle. So let’s make this script!
What’s selenium?
Selenium is likely one of the freed from the automated testing frameworks used to automate net browsers. We will use selenium with a number of languages like Java, Python, Ruby, C#, and so on. Selenium is greater than only a single device; it’s a set of instruments, every of which caters to a sure group’s Selenium QA testing necessities. Selenium Built-in Growth Setting(IDE), Selenium Distant Management (RC), WebDriver, Selenium grid are instruments of selenium.
To automate the browser right here, we’ll use the selenium WebDriver device. Selenium WebDriver is an internet framework that allows you to execute cross-browser checks. This device is used for automating web-based software testing to confirm that it performs expectedly.
Set up and getting began
When beginning a brand new undertaking in python, the perfect method is to create a brand new atmosphere and work in it. That is useful as a result of it separates different tasks and their dependencies in distinct locations, which permits for simple deployment if wanted, and clear package-managing.
python -m venv env_name
After working this in cmd, the folder might be created with the title of your atmosphere title. After creating the atmosphere, activate it and now we’ll set up our required dependencies for our undertaking.
Set up Selenium libraries for Python utilizing pip. Extra data on set up might be discovered here.
pip set up selenium
We’ve got to put in an internet driver that Selenium will make the most of to make use of the browser. We will use any browser, however right here, we’ll use Chrome-Driver for Google Chrome/Chromium. You may obtain the net driver here.
For creating an internet software, we have now used Flask. For putting in Flask in your digital atmosphere, use the command beneath.
pip set up -U Flask
We’ve got to put in another packages for this undertaking. Create a necessities.txt file, add this into this file and run the beneath command. This can set up all of the packages that are wanted on this undertaking.
pip set up -r necessities.txt
1. Creating .env file
To retailer the e-mail ID and passwords, we’ll create a .env file and get the login credentials from the .env file.
Ensure that the format of the .env is precisely similar as beneath. Right here the primary two env variables i.e. EMAIL & PASSWORD are used for LinkedIn Login, and the final two i.e. SENDER_EMAIL & SENDER_PASSWORD are used for Electronic mail authentication, which is utilized in exceptionMail.py file.
2. Making a python file for sending mail.
If any exception happens, or if a birthday is efficiently wished, or if there isn’t any birthday right this moment, we’ll ship a mail to the consumer. To take action, use the code beneath.
import smtplib, ssl
from e mail.mime.textual content import MIMEText
from e mail.mime.multipart import MIMEMultipart
import time
import os
# Outlined sender e mail credentials within the .env file and accessing utilizing os strategies
sender_email = os.getenv("SENDER_EMAIL")
password = os.getenv("SENDER_PASSWORD")
def sendMail(receiver_email, bodyMessage):
message = MIMEMultipart("various")
message["Subject"] = "RE: Your computerized birthday wisher"
message["From"] = sender_email
message["To"] = receiver_email
# # Flip these into plain/html MIMEText objects
part1 = MIMEText(bodyMessage, "plain")
# Add HTML/plain-text elements to MIMEMultipart message
# The e-mail shopper will attempt to render the final half first
message.connect(part1)
# Create safe reference to server and ship e mail
context = ssl.create_default_context()
attempt:
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 despatched"
besides Exception as e:
print(e)
return "Mail couldn't despatched Exception is : {}".format(e)
3. Get the required phrases utilizing Examine components
By utilizing the “examine component”, we are able to detect that the e-mail textual content field component accommodates the ID ‘username’. The password’s id is comparable, with its id being ‘password’. We will make the most of the ‘find_element_by_id’ operate to get these components within the HTML. After acquiring the textual content field components, we are able to name the ‘send_keys(string)’ technique on these bins with a specified string.

4. Making a Perform for Login and wishing glad birthday.
Create a python file named linkedInBirthday.py and replica the beneath code in that file.
We are going to import the mandatory 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.choices import Choices
from selenium.webdriver.frequent.by import By
from selenium.webdriver.frequent.keys import Keys
import pandas as pd
from selenium.webdriver.frequent.action_chains import ActionChains
import os
Then, we’ll use the username and password from the .env file.
# Outlined sender e mail credentials within the .env file and accessing utilizing os strategies
usr = os.getenv("EMAIL")
pwd = os.getenv("PASSWORD")
First, we’ll go to the connection web page and scrape all of the connection’s particulars, profile hyperlinks, and retailer it within the CSV file.
When the entire connection is identical as within the CSV file, then we received’t scrape the consumer particulars, whereas working the script once more.

We are going to iterate by way of all these pages and scrape all of the connection particulars.

After scraping all consumer particulars, we’ll use these profile hyperlinks and scrape the birthdate of every connection from the contact data part.

Observe the code given beneath.
#Declare the beneath variables
header = ['name', 'Link', 'image', 'Bithday']
knowledge = []
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("Electronic mail 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"]/kind/div[3]/button')
login_box.click on()
time.sleep(10)
print('logged in')
time.sleep(3)
driver.get(
"https://www.linkedin.com/search/outcomes/individuals/?community=%5Bpercent22Fpercent22percent5D&origin=FACETED_SEARCH&sid=RUx")
time.sleep(4)
# Scrap the listing of profiles
def get_profile_of_a_page():
place = 0
birthdayslist = driver.find_elements_by_class_name(
'entity-result__item')
for b in birthdayslist:
profileLink = b.find_element_by_tag_name("a")
title = profileLink.textual content
linkk = profileLink.get_attribute("href")
attempt:
imageTagFinder = b.find_element_by_tag_name("img")
picture = imageTagFinder.get_attribute("src")
besides:
picture = 'https://www.pngarea.com/pngm/90/6980003_profile-icon-png-facebook-default-profile-picture-girl.png'
connList[position] = {'hyperlink': linkk, 'title': title, 'picture': picture}
place = place + 1
# Scrolling a full-page
def scroll_till_end():
attempt:
html = driver.find_element_by_tag_name('html')
html.send_keys(Keys.END)
besides Exception as e:
print(str(e))
# transferring to subsequent web page
def next_page():
attempt:
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 on();", next_button)
time.sleep(4)
# break
besides Exception as e:
print(e)
# Add all connection particulars into the CSV file
def addConnectionToCsv():
for consumer 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 on()
time.sleep(2)
attempt:
birthdate = driver.find_element_by_class_name(
'pv-contact-info__contact-item.t-14.t-black.t-normal').textual content
time.sleep(4)
knowledge.append([connList[user]['name'], connList[user]
['link'], connList[user]['image'], birthdate])
loopVar = loopVar + 1
# write a number of rows
besides Exception as e:
print(e)
with open('linkedinProfiles.csv', 'w', encoding='UTF8', newline='') as f:
author = csv.author(f)
# write the header
author.writerow(header)
author.writerows(knowledge)
# checks if right this moment is somone's birthday or not
def isbirthday():
right this moment = date.right this moment()
# Textual month, day and 12 months
d2 = right this moment.strftime("%B %#d %Y")
currentDate = d2.break up()
currentDate.pop()
dataOfCsv = pd.read_csv("linkedinProfiles.csv")
# changing column knowledge to listing
connectionBirthdates = dataOfCsv['Bithday'].tolist()
for birthday in vary(len(connectionBirthdates)):
if connectionBirthdates[birthday].break up() == currentDate:
index.append(birthday)
# Depend knowledge in CSV
def dataInCSV():
attempt:
dataInCsv = pd.read_csv("linkedinProfiles.csv")
besides Exception as e:
print(e)
return 0
listOfData = dataInCsv['Bithday'].tolist()
print("totalCSVdata : ", len(listOfData))
return len(listOfData)
# Fetch the entire connection
def totalConnection():
totConnection = driver.find_element_by_class_name(
'pb2.t-black--light.t-14').textual content
conn = totConnection.break up()
conn.pop()
print("totalConnectiondata : ", int(conn[0]))
return int(conn[0])
# Get the listing whose birthday is right this moment
def getBirthdayList():
listCount = 0
with open('linkedinProfiles.csv') as csv_file:
csv_reader = csv.reader(csv_file)
subsequent(csv_reader)
row = listing(csv_reader)
# fhandle = open('linkedinProfiles.csv')
for ind in index:
rowneeded = row[ind]
birthdayList[listCount] = {
'title': rowneeded[0], 'hyperlink': rowneeded[1], 'picture': rowneeded[2], 'birthday': rowneeded[3]}
listCount = listCount + 1
def pageToScrape():
attempt:
response = driver.page_source
soup = BeautifulSoup(response, 'html.parser')
all_pages = soup.find_all(class_="artdeco-pagination__indicator artdeco-pagination__indicator--number ember-view")
world last_page
if len(all_pages)>0:
print("whole pages:",len(all_pages))
last_page = all_pages[-1].textual content
print("last_page",all_pages[-1].textual content)
else:
print("No knowledge")
last_page = 1
besides:
print("Cannot discover the component")
# Verify the depend of connections in CSV and the precise connection depend
if dataInCSV() == totalConnection():
print("Discovering the bithday of connections")
isbirthday()
getBirthdayList()
else:
print("Scraping the connections detailsn")
pageToScrape()
for i in vary(int(last_page)):
scroll_till_end()
get_profile_of_a_page() # profile scrapping operate!
scroll_till_end()
next_page()
time.sleep(4)
addConnectionToCsv()
print("Discovering the bithday of connections")
isbirthday()
getBirthdayList()
print(index)
# Sends the message
def sendMessage():
world message
world index
world connList
if index != []:
message = "Birthday wished"
connListFromCSV = pd.read_csv("linkedinProfiles.csv")
BirthdayConnLinks = connListFromCSV['Link'].tolist()
for indexNumber in index:
hyperlink = BirthdayConnLinks[indexNumber]
# Logic to ship Message
driver.get(hyperlink)
time.sleep(4)
msg = driver.find_element_by_link_text('Message').click on()
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('Pleased Birthday')
time.sleep(3)
ship = driver.find_element_by_class_name(
'msg-form__send-button.artdeco-button.artdeco-button--1')
ActionChains(driver).move_to_element(
ship).click on(ship).carry out()
time.sleep(3)
attempt:
shut = 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 shut:
closebut.click on()
besides:
print("No shut button discovered")
exp = "There's some downside sending the message, attempt once more or contact the developer."
sendMail(receiver_email=usr, bodyMessage=exp)
time.sleep(3)
print('Message ship')
else:
message = "No extra birthday for right this moment"
sendMessage()
return message, birthdayList
driver.shut()
You’ll find the entire script here.
Now we’ll use this runScript() operate in our flask undertaking.
What’s Flask?
Flask is a python net framework, for growing net purposes.
Right here, we’ll use Flask for working our script and Displaying consumer info or another error that happens whereas working the script.
The File Construction

We are going to create a flask app named flask_app.py. On this file, we’ll import the required modules and a few capabilities of linkedInBirthday.py, add the next 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('house.html')
@app.route('/running-script')
def running_script():
knowledge = runScript()
print(knowledge[0])
session['messages'] = knowledge[0]
world birthdayData
world index
birthdayData = knowledge[1]
return redirect(url_for('.success', messages = knowledge[0]))
@app.route('/success')
def success():
# messeges = request.args['messages']
world birthdayData
messages = session['messages']
return render_template('/success.html', messages = messages, birthday = birthdayData)
if __name__ == '__main__':
app.run(debug=True)
Now we’ll create two HTML information within the template folder.
The primary house.html, add the next code in it. It’s the start-up web page once we run the flask app.
<!DOCTYPE html>
<html lang="en">
<head>
<hyperlink
rel="stylesheet"
sort="textual content/css"
href="{{ url_for('static',filename='types/house.css') }}"
/>
<hyperlink rel="preconnect" href="https://fonts.googleapis.com" />
<hyperlink rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<hyperlink
href="https://fonts.googleapis.com/css2?household=Poppins&show=swap"
rel="stylesheet"
/>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Suitable" content material="IE=edge" />
<meta title="viewport" content material="width=device-width, initial-scale=1.0" />
<title>Fb-script</title>
</head>
<physique>
<div class="signupStyle">
<div id="content material" model="show: none" class="ProcessingDiv">
<middle><h2>Executing the Script..............</h2></middle>
</div>
<a
href="/running-script"
class="btnn"
onclick="return loader()"
id="button"
>Execute the Script</a
>
</div>
<!-- </kind> -->
<script>
operate loader() {
doc.getElementById("button").model.show = "none";
doc.getElementById("content material").model.show = "block";
}
</script>
</physique>
</html>
The second is success.html. This HTML template will show the standing of the runScript() and print Person info if there’s a birthday right this moment out of your connections. Add the next code to it.
<!DOCTYPE html>
<html lang="en">
<head>
<hyperlink
rel="stylesheet"
sort="textual content/css"
href="{{ url_for('static',filename='types/house.css') }}"
/>
<hyperlink rel="preconnect" href="https://fonts.googleapis.com" />
<hyperlink rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<hyperlink
href="https://fonts.googleapis.com/css2?household=Poppins&show=swap"
rel="stylesheet"
/>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Suitable" content material="IE=edge" />
<meta title="viewport" content material="width=device-width, initial-scale=1.0" />
<title>Success</title>
</head>
<physique>
<div class="outerDiv">
<div class="BasicLayout">
<p><h1>Script Executed, {{ messages }}</h1></p>
<div id="birthCard" class="flexDir">
{% for b in birthday %}
<div class="profileCards">
<div>
<img class = "profileImage" alt="" src="{{birthday[b]['image']}}" />
</div>
<div>
<a mode="text-decoration: none;" href="{{birthday[b]['link']}}" goal="_blank"><div class = "profileName">{{ birthday[b]['name'] }}</div></a>
<div>{{ birthday[b]['birthday'] }}</div>
</div>
</div>
{% endfor %}
</div>
</div>
</div>
</physique>
</html>
For a CSS file create a folder like this. –> static/types. In types, folder create CSS file title house.css and add following code in it.
physique {
background: white;
font-family: "Poppins", sans-serif;
}
.btnn {
text-decoration: none;
define: none;
padding: 10px 20px;
background: rgb(190, 255, 194);
coloration: rgb(2, 2, 2);
border: none;
border-radius: 3px;
cursor: pointer;
transition: all 0.5s;
margin: 10px auto;
width: max-content;
text-align: middle;
}
.btnn:hover {
background-color: rgb(85, 255, 96);
}
.signupStyle {
show: flex;
justify-content: middle;
align-content: middle;
margin-top: 300px;
flex-direction: column;
}
/* For format function */
.BasicLayout {
width: 1100px;
top: auto;
max-width: 75%;
padding: 30px 50px;
float: left;
margin: 0 auto;
margin-bottom: 2em;
show: flex;
flex-direction: column;
}
.outerDiv {
show: flex;
}
.profileCards {
margin-top: 25px;
show: flex;
width: 310px;
border-radius: 5px;
margin-right: 5px;
justify-content: space-around;
padding: 15px;
align-items: middle;
background-color: rgb(223, 255, 225);
}
.profileImage {
width: 110px;
top: 110px;
border-radius: 50%;
}
.profileName {
font-size: 1.6em;
font-weight: 500;
coloration: rgb(55, 255, 68);
}
.flexDir{
show: flex;
hole: 10px;
}
.ProcessingDiv{
show: flex;
top: 100%;
}
To run the flask app
python flask_app.py
After working this script, copy the URL from the command immediate and open it into the browser. Click on on the “Execute the script” button. The script will want if there are any birthdays and can show title and birthday of consumer whom the birthday is wished.


That’s it!
You can even put this script to run each day utilizing cron job and you may be wishing Birthday needs to your LinkedIn pals each day!