Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
artur.sniegowski committed Sep 8, 2022
2 parents bbfaac6 + 9eccf6c commit abbc55a
Show file tree
Hide file tree
Showing 280 changed files with 8,095 additions and 0 deletions.
2 changes: 2 additions & 0 deletions Automated_Amazon_price_tracker/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MY_EMAIL = "EXAMPLE.USER@gmail.com"
GMAIL_APP_PASSWORD = "GMAIL_APP_PASSWORD"
41 changes: 41 additions & 0 deletions Automated_Amazon_price_tracker/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Automated_Amazon_price_tracker

This program will works like a bot, that in first step scrapes the data from a given Amazon website product, and looks for the price and title of this product. In the next step this program can be set to check the price once per a day, with the use of https://www.pythonanywhere.com/ , and if the price drops below the target value set by the user, it will send an email notification, to make sure we don't miss this bargain!</br>


---

Necessary steps to make the program work:</br>

1. Create a Gmail account that the program can use and generate an app_pssword for the account (https://help.prowly.com/how-to-create-use-gmail-app-passwords).</br>

2. After creating the Gmail account, we have to change the name of .env.example to .env and define the environmental variables according to our account:</br>
MY_EMAIL = "EXAMPLE.USER@gmail.com"</br>
GMAIL_APP_PASSWORD = "GMAIL_APP_PASSWORD"</br>

3. The user has to adjust the starting variables in the main.py:</br>
*TARGET_PRICE* = 800.00 - target price needs to be adjusted, example 800.00 </br>
*AMAZON_PRODUCT_TO_TRACK_URL* = "https://www.amazon.com/OnePlus-Smartphone-Unlocked-co-Developed-Hasselblad/dp/B07XM54RWB" - the Amazon url of the product we want to track, example onplus 10 url </br>
*EMAIL_RECIVER* = "example@proton.me - the email where the program will send the notification. </br>
*MY_HTTP_HEADER* = { } - define your header as dictionary, you can use http://myhttpheader.com/ to retrieve the data. This is needed to be able to read with request the Amazon url and to escape the captcha check. </br>



Hint:</br>
In order to find a good target price, we can use
https://camelcamelcamel.com/</br>

---

Example of received email:</br>
![Screenshot](docs/img/01_example_email.png)

---


**The program was developed using python 3.10.6, BeautifulSoup, requests, dotenv, smtplib**


In order to run the program, you have to execute main.py.


Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions Automated_Amazon_price_tracker/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# main program
from web_scrapper import AmazonScrapper
from notification_manager import NotificationManager

# env variables !
from dotenv import load_dotenv
load_dotenv()
import os

################################################################################
# SET THESE VARIABLES !!
# target price
TARGET_PRICE = 800.00
# COPY here your own url, amazon product url
AMAZON_PRODUCT_TO_TRACK_URL = "https://www.amazon.com/OnePlus-Smartphone-Unlocked-co-Developed-Hasselblad/dp/B07XM54RWB"
# email adress where we want to send the notification to, when the prices drops
# below the given threshold
# dont forget to adjust !
EMAIL_RECIVER = "example@proton.me"#"example@proton.me"
# define your header
# You'll need to pass along some headers in order for the request to return the actual website HTML
# go to http://myhttpheader.com/ to check these values and update them accordingly.
MY_HTTP_HEADER = {
# "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
"Accept-Encoding":"gzip, deflate",
"Accept-Language":"en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7,de;q=0.6,la;q=0.5,ar;q=0.4",
# "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
# "Connection" : "keep-alive",
"DNT":"1",
"Connection" : "close",
"Upgrade-Insecure-Requests":"1",
}
# MY_HTTP_HEADER = {
# "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:66.0) Gecko/20100101 Firefox/66.0",
# "Accept-Encoding":"gzip, deflate",
# "Accept-Language":"en-US,en;q=0.9,pl-PL;q=0.8,pl;q=0.7,de;q=0.6,la;q=0.5,ar;q=0.4",
# "Accept":"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
# "DNT":"1",
# "Connection":"close",
# "Upgrade-Insecure-Requests":"1"
# }
################################################################################



################################################################################
## sensitive data ###
#####################
# user defined email and app password - has to be GMAIL !
# env variables ! - dont change here !
MY_EMAIL = os.environ.get('MY_EMAIL')
GMAIL_APP_PASSWORD = os.environ.get('GMAIL_APP_PASSWORD')
################################################################################




# creating an email sender manager object for sending emails
email_sender_manager = NotificationManager(email_app_password=GMAIL_APP_PASSWORD
,email_from=MY_EMAIL)



####################scraping the data from given amazon url#####################
# creatign an object for scrapign data
amazon_scraper = AmazonScrapper(AMAZON_PRODUCT_TO_TRACK_URL, headers = MY_HTTP_HEADER)
product_price = amazon_scraper.return_the_price_of_product()
product_title = amazon_scraper.return_the_title_of_product()
# if price below our target price, send an email notification

if product_price: # if product price found
print(product_price)
if product_price <= TARGET_PRICE:
# creating message for the email
message_content = f"{product_title}\nnow:${product_price}\n{AMAZON_PRODUCT_TO_TRACK_URL}"
# sending an email
email_sender_manager.send_gmail_mail(email_title="Amazon Price Alert!",
message_to_send=message_content,
email_to=EMAIL_RECIVER)
41 changes: 41 additions & 0 deletions Automated_Amazon_price_tracker/notification_manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# This class is responsible for sending notifications.
# class responsible for sending emails
import smtplib

class NotificationManager:
"""
managing the sending of emails with a gamil account
This class is responsible for sending notifications with the deal flight details.
"""
def __init__(self, email_app_password: str, email_from: str) -> None:
self.email_app_password = email_app_password
self.email_from = email_from


def send_gmail_mail(self, email_title: str, message_to_send: str, \
email_to: str) -> None:
"""
sends email from a gmail account
"""
# using encode utf-8 to escape the UnicodeEncodeError for specific characters
email_message = lambda title, content: f"Subject:{title}\n\n{content}".encode('utf-8')

with smtplib.SMTP("smtp.gmail.com", port=587) as connection:
connection.starttls() # making the conection secure
result = connection.login(user=self.email_from, password=self.email_app_password)
connection.sendmail(from_addr=self.email_from,
to_addrs=email_to,
msg=email_message(title=email_title,content=message_to_send))


def send_emails(self, list_of_users : list[dict], email_title: str, \
message_to_send: str) -> None:
"""
send a email to a list of defined users
"""
for user in list_of_users:
self.send_gmail_mail(
email_title=email_title,
message_to_send=message_to_send,
email_to=user['email']
)
Binary file added Automated_Amazon_price_tracker/requirements.txt
Binary file not shown.
1 change: 1 addition & 0 deletions Automated_Amazon_price_tracker/runtime.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Python 3.10.6
73 changes: 73 additions & 0 deletions Automated_Amazon_price_tracker/web_scrapper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
# class for scraping data
from bs4 import BeautifulSoup
import requests
import lxml

class AmazonScrapper:
def __init__(self, product_website_url: str, **kwargs) -> None:
self.product_website_url = product_website_url
self.response = requests.Response()
self.soup = BeautifulSoup()
self.headers = kwargs.get('headers', None)

# init values
self._get_raw_data_from_website()

def _get_raw_data_from_website(self) -> None:
"""
returns raw data from the given website,
the response will be populated with that data.
the soup object will be poppulated with data
The text() method of the Request interface reads the request body and
returns it as a promise that resolves with a String.
The response is always decoded using UTF-8.
"""
self.response = requests.get(url= self.product_website_url,
headers=self.headers)
self.response.raise_for_status() # check for any errors
# # in case of encoding problems - if the encoding cant be resolved from the request
# self.response.encoding = 'utf-8'

# print(self.response.text)
# getting bs4 / BeautifulSoup object
# self.soup = BeautifulSoup(self.response.text, 'html.parser')
self.soup = BeautifulSoup(self.response.text, "lxml")


def return_the_price_of_product(self) -> float :
"""
return the price of the product as an float object, if found
otherwise returns None
"""
price_element = self.soup.select_one(selector="div#corePrice_feature_div div.a-section span.a-price span.a-offscreen")

if price_element:
price = price_element.get_text().strip()
try:
price = float(price.split("$")[1])
# price = float(price[1:])
except SyntaxError:
print(f"{price} : Issue with casting to float !!")
else:
return price

return None


def return_the_title_of_product(self) -> str:
"""
returns the title of the product, if it cant fidn it,
it will return empty string
"""

title_element = self.soup.select_one(selector="div#titleSection h1#title span#productTitle")

if title_element:
title = title_element.get_text().strip()

return title

return ""
2 changes: 2 additions & 0 deletions Automating_job_applications_on_linkedin/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
MY_LINKEDIN_EMAIL = "YOUR.EMAIL@gmail.com"
MY_LINKEDIN_PASSWORD = "Your_password"
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
---------ChromeDriver 104.0.5112.79 (2022-08-03)---------
Supports Chrome version 104
55 changes: 55 additions & 0 deletions Automating_job_applications_on_linkedin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Automating_job_applications_on_linkedin

This is an automated job application bot. The program will use selenium WebDriver
to automate applying for jobs on LinkedIn with the "Easy Apply" function to send applications to all the jobs that meet your criteria (instead of just a single listing).
In the first step, it will log in to your LinkedIn account, and then go to the specific search job URL defined in the program by the user.
After accessing this URL, the bot will go through each of the application and asses if there is a function of Easy Apply.
If it doesn't exist, the job application will be skipped, and the bot will move to the next job application.
After finding the Easy Apply button, the bot will submit the first step of application by pressing it.
In the next step, the bot will validate how the application form looks.
If the application form will have the button next which indicates a multistep application, the bot will terminate the application,
only application with "submit application" will be accepted.
The bot will submit the application, and fill in the given phone number and send out the application.
After that, the bot will move to the next job application.  



Necessary steps to make the program work:</br>
1. Install Chrome browser https://www.google.com/intl/en_uk/chrome/ </br>
2. Download chrome driver (don't forget to match the version of your chrome with the version of the chrome driver) https://chromedriver.storage.googleapis.com/index.html?path=104.0.5112.79/, and unzip the file for your OS.
Mark the DIR to the chromedriver.exe file and adjust the *chrome_driver_path* in main.py. </br>
3. Sign up to LinkedIn  https://www.linkedin.com/ and configure your Profile. </br>
Make sure you've signed up to LinkedIn and save your email and password somewhere for later use.</br>
Upload your resume by going to Me -> Settings & Privacy -> Data Privacy -> Job Seeking Preferences -> Job Application Settings.</br>
NOTE: Do not enable 2-factor authentication/phone number verification while we are using Selenium.</br>
4. After creating the LinkedIn account, we have to change the name of .env.example to .env and define the environmental variables according to our account:</br>
MY_LINKEDIN_EMAIL = "YOUR.EMAIL@gmail.com"</br>
MY_LINKEDIN_PASSWORD = "Your_password"</br>
5. The user has to adjust the starting variables in the main.py:</br>
*PHONE_NUMBER* - phone number to be filled in the form during application.</br>
*WEBSITE_URL_FOR_THE_DRIVER* - URL for job search.</br>


---

**Example of view Easy Apply application:**</br>

![Screenshot](docs/img/01_easy_apply.png)</br>


**Example of view of submitting application:**</br>

![Screenshot](docs/img/02_submiting_applicatio.png)</br>


**Example of view of invalid form with a next button - multistep application is not supported:**</br>

![Screenshot](docs/img/03_inalid_form_next.png)</br>

---


**The program was developed using python 3.10.6, selenium**


In order to run the program, you have to execute main.py.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit abbc55a

Please sign in to comment.