How to Develope a Hotel Price Monitoring Tool with Python?
Tags: api, hotel, price, monitoring
Published: 2023-05-01 08:25:56

In the world of travel and tourism, finding the best deals on hotels is of utmost importance. 

With the plethora of Online Travel Agencies (OTAs) available today, keeping [track of hotel prices](https://www.makcorps.com/blog/hotel-pricing-monitoring-definition-importance-how-to-do/) across different platforms can be a daunting task. 

In this blog post, we will guide you through creating a simple hotel price monitoring tool using Python. 

This tool will track hotel prices for specific dates and send an email notification whenever a better offer is available.

## Prerequisites

Before starting, ensure that you have Python 3.x installed on your system. You'll also need to install the requests library for handling HTTP requests:

```
mkdir hotelpricetracker
```

## Choose a Hotel API

To gather accurate and up-to-date hotel pricing information, we'll need access to a reliable [Hotel Price API](https://www.makcorps.com/). There are several APIs available in the market, such as Makcorps, Expedia, Booking.com, or Skyscanner. 

Depending on your preference and budget, you can choose the one that best suits your needs. 

Keep in mind that some APIs may require registration and may have usage limitations.

## Set up the Python Environment

Create a new folder for your project:

```
mkdir hotel_price_monitor
```
Next, create a Python script within the folder. We'll name the file hotel.py.

We will also install a library that can make an HTTP connection to the host website. We are going to use requests for that purpose. Here is how you can install it.

```
pip install requests
```

## Write the Price Monitoring Script

Start by importing the necessary libraries:

```
import requests
```

Currently, we are going to use a for loop to make a GET request to the hotel API for each date individually.

```
o={}
l=[]
ExpediaPrice=[]
ExpediaDate=[]

BookingPrice=[]
BookingDate=[]

for x in range(0,5):
    date='2023-03-{}/2023-03-{}'.format(x+11,x+12)
    target='https://api.makcorps.com/hotelprice/The%20lenox/114134/1/1/2023-03-{}/2023-03-{}?api_key=Your-API-Key'.format(x+11,x+12)

    resp=requests.get(target).json()

    for i in range(0,len(resp['comparison'][0])):
        if(resp['comparison'][0][i]['vendor{}'.format(i+1)] == 'Booking.com'):
            o["BookingPrice"]=resp['comparison'][0][i]["price{}".format(i+1)]
            o["dateB"]=date
            l.append(o)
            o={}
            continue

        if(resp['comparison'][0][i]['vendor{}'.format(i+1)] == 'Expedia.com'):
            o["ExpediaPrice"]=resp['comparison'][0][i]["price{}".format(i+1)]
            o["dateE"]=date
            l.append(o)
            o={}
            continue
```
Here are the step-by-step explanations of what we have done:

- Declared empty arrays and objects.
- Used a for loop to run five times, as we have five days of holidays to check prices for days falling between those dates.
- Made a GET request to the API using the requests library.
- Ran another for loop to extract prices from each response. Specifically, we extracted prices of booking.com and expedia.com and stored them in an object called o.
- At the end of the first for loop, the list object l will have all the prices and respective dates.

If you are curious about what the API response looks like, you can check it out.

```
{
  "comparison": [
    [
      {
        "vendor1": "Expedia.com",
        "price1": "$169",
        "tax1": "$30"
      },
      {
        "vendor2": "Hotels.com",
        "price2": "$169",
        "tax2": "$30"
      },
      {
        "vendor3": "Booking.com",
        "price3": "$152",
        "tax3": "$27"
      },
      {
        "vendor4": "eDreams",
        "price4": "$152",
        "tax4": "$27"
      },
      {
        "vendor5": "Orbitz.com",
        "price5": "$169",
        "tax5": "$30"
      },
      {
        "vendor6": "Travelocity",
        "price6": "$169",
        "tax6": "$30"
      },
      {
        "vendor7": "Prestigia.com",
        "price7": "$161",
        "tax7": "$39"
      },
      {
        "vendor8": "Hurb",
        "price8": "$169",
        "tax8": "$35"
      },
      {
        "vendor9": "Algotels",
        "price9": null,
        "tax9": null
      },
      {
        "vendor10": "StayForLong",
        "price10": null,
        "tax10": null
      },
      {
        "vendor11": "Vio.com",
        "price11": null,
        "tax11": null
      },
      {
        "vendor12": "Official Site",
        "price12": null,
        "tax12": null
      },
      {
        "vendor13": "Priceline",
        "price13": null,
        "tax13": null
      },
      {
        "vendor14": "ZenHotels.com",
        "price14": null,
        "tax14": null
      },
      {
        "vendor15": "Agoda.com",
        "price15": null,
        "tax15": null
      },
      {
        "vendor16": "Trip.com",
        "price16": null,
        "tax16": null
      }
    ],
    [
      
    ]
  ]
}
```
Next, we need to create separate lists for each OTA. The purpose of doing this is to later sort the prices in ascending order.

```
for p in range(0,len(l)):
    try:
        ExpediaPrice.append(int(l[p]['ExpediaPrice'].replace('$','')))
        ExpediaDate.append(l[p]['dateE'])
    except:
        BookingPrice.append(int(l[p]['BookingPrice'].replace('$','')))
        BookingDate.append(l[p]['dateB'])
```
We have created four different arrays named ExpediaPrice, ExpediaDate, BookingPrice, and BookingDate.

ExpediaPrice holds the integer values of prices from Expedia, while ExpediaDate stores the corresponding dates of those prices from Expedia.com. Similarly, BookingPrice has integer values of prices from Booking.com, and BookingDate contains the dates corresponding to those prices from Booking.com.

Now that we have the data, our objective is to sort the prices in ascending order so that we can identify the cheapest price and the date on which it is available. To accomplish this, we can use the .sort() method to sort the ExpediaPrice and BookingPrice arrays.

```
ExpediaPrice.sort()
BookingPrice.sort()
```
We have the sorted price but we do not know the dates of these new arrays because the index position of each price has changed now. So, what we can do is record the index position of each price from the original array(without sorting). Through this, we will be able to track down their dates from ExpediaDate and BookingDate arrays.

For this task, we are going to use [Numpy](https://numpy.org/). It is already installed all you have to do is import this into the file.

```
ExpediaIndex = numpy.array(ExpediaPrice)
BookingIndex = numpy.array(BookingPrice)

sort_index_expedia = numpy.argsort(ExpediaIndex)
sort_index_booking = numpy.argsort(BookingIndex)

ExpediaPrice.sort()
BookingPrice.sort()
```

We are using the .array() function to insert the array list that requires sorting. Next, we are using the .argsort() function from numpy, which provides a list of indices in ascending order. This is also referred to as indirect sorting.

The sort_index_expedia and sort_index_booking arrays will contain the original position of each price. With this information, we can now determine the date of the sorted price list array as well.

Once you print the output, you will be able to see the cheapest price and date from each OTA.

```
print("Cheapest Price from Expedia is", ExpediaPrice[0])
print("Cheapest Date on Expedia is", ExpediaDate[sort_index_expedia[0]])

print("Cheapest Price from Booking.com is", BookingPrice[0])
print("Cheapest Date onBooking.com is", BookingDate[sort_index_booking[0]])
```
Now, all that's left to do is to email yourself the best vacation offer.

## How To Mail Yourself?

To send emails using our Gmail account through mail, we will be utilizing the [smtplib](https://docs.python.org/3/library/smtplib.html) library. It is not necessary to install the library separately as it is already included in the Python installation.

```
def mail(bookingPrice, bookingDate, expediaPrice, expediaDate):
 attackMsg = '''\
Cheapest Price from Booking.com is {bookingPrice} \nCheapest Date for Booking.com is {bookingDate} \nCheapest Price from Expedia.com is {expediaPrice} \nCheapest Date for Expedia.com is {expediaDate}

'''.format(bookingPrice=bookingPrice, bookingDate=bookingDate, expediaPrice=expediaPrice, expediaDate=expediaDate)

 server = smtplib.SMTP('smtp.gmail.com', 587)
 server.ehlo()
 server.starttls()
 server.login("from@gmail.com", "your_passowrd")
 SUBJECT = "Price Alert"
 message = 'From: from@gmail.com \nSubject: {}\n\n{}'.format(SUBJECT, attackMsg)
 server.sendmail("from@gmail.com", 'send_to@gmail.com', message)

 server.quit()
 return True
```
The function "mail" is defined in the first line, which takes four arguments: bookingPrice, bookingDate, expediaPrice, and expediaDate. The second step involves creating a string variable called "attackMsg" using triple quotes. This variable includes placeholders ({}) for the four arguments of the function. The "format" method is used to replace the placeholders with the actual values of the arguments.

The next four lines establish a connection to a Gmail SMTP server using the smtplib library. The "ehlo" and "starttls" methods initiate a secure connection, and the "login" method authenticates the user with the SMTP server using their email address and password.

The subject and body of the email message are defined in two subsequent lines. The "message" variable contains a formatted string that includes the "SUBJECT" variable and the "attackMsg" variable.

The email message is sent using the "sendmail" method of the SMTP object, with the email being sent from the email address specified in the first argument (from@gmail.com) to the email address specified in the second argument (send_to@gmail.com).

The last two lines close the connection to the SMTP server using the "quit" method and return "True" to indicate that the email was successfully sent. 

Finally, you will receive an email that looks like the one described below:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3duysnenqlrk2z1vnup9.png)

## Here Is the Compltete Code

Naturally, you can utilize this code to monitor prices over an extended period of time. With this information, you can stay updated on the prices offered by your rivals as well.

```
import requests
import smtplib, ssl
import numpy


def mail(bookingPrice, bookingDate, expediaPrice, expediaDate):
 attackMsg = '''\
Cheapest Price from Booking.com is {bookingPrice} \nCheapest Date for Booking.com is {bookingDate} \nCheapest Price from Expedia.com is {expediaPrice} \nCheapest Date for Expedia.com is {expediaDate}

'''.format(bookingPrice=bookingPrice, bookingDate=bookingDate, expediaPrice=expediaPrice, expediaDate=expediaDate)

 server = smtplib.SMTP('smtp.gmail.com', 587)
 server.ehlo()
 server.starttls()
 server.login("from@gmail.com", "your_passowrd")
 SUBJECT = "Price Alert"
 message = 'From: from@gmail.com \nSubject: {}\n\n{}'.format(SUBJECT, attackMsg)
 server.sendmail("from@gmail.com", 'send_to@gmail.com', message)

 server.quit()
 return True


# l=[{'ExpediaPrice': 565, 'dateE': '2023-03-11/2023-03-12'}, {'BookingPrice': 565, 'dateB': '2023-03-11/2023-03-12'}, {'ExpediaPrice': 295, 'dateE': '2023-03-12/2023-03-13'}, {'BookingPrice': 295, 'dateB': '2023-03-12/2023-03-13'}, {'ExpediaPrice': 445, 'dateE': '2023-03-13/2023-03-14'}, {'BookingPrice': 445, 'dateB': '2023-03-13/2023-03-14'}, {'ExpediaPrice': 455, 'dateE': '2023-03-14/2023-03-15'}, {'BookingPrice': 455, 'dateB': '2023-03-14/2023-03-15'}, {'ExpediaPrice': 385, 'dateE': '2023-03-15/2023-03-16'}, {'BookingPrice': 385, 'dateB': '2023-03-15/2023-03-16'}]
o={}
l=[]
ExpediaPrice=[]
ExpediaDate=[]

BookingPrice=[]
BookingDate=[]

for x in range(0,5):
    date='2023-03-{}/2023-03-{}'.format(x+11,x+12)
    target='https://api.makcorps.com/hotelprice/The%20lenox/114134/1/1/2023-03-{}/2023-03-{}?api_key=Your-API-Key'.format(x+11,x+12)
    print(target)
    resp=requests.get(target).json()

    for i in range(0,len(resp['comparison'][0])):
        if(resp['comparison'][0][i]['vendor{}'.format(i+1)] == 'Booking.com'):
            o["BookingPrice"]=resp['comparison'][0][i]["price{}".format(i+1)]
            o["dateB"]=date
            l.append(o)
            o={}
            continue

        if(resp['comparison'][0][i]['vendor{}'.format(i+1)] == 'Expedia.com'):
            o["ExpediaPrice"]=resp['comparison'][0][i]["price{}".format(i+1)]
            o["dateE"]=date
            l.append(o)
            o={}
            continue

        # if(len(o) != 0):

for p in range(0,len(l)):
    try:
        ExpediaPrice.append(int(l[p]['ExpediaPrice'].replace('$','')))
        ExpediaDate.append(l[p]['dateE'])
    except:
        BookingPrice.append(int(l[p]['BookingPrice'].replace('$','')))
        BookingDate.append(l[p]['dateB'])


ExpediaIndex = numpy.array(ExpediaPrice)
BookingIndex = numpy.array(BookingPrice)

sort_index_expedia = numpy.argsort(ExpediaIndex)
sort_index_booking = numpy.argsort(BookingIndex)

ExpediaPrice.sort()
BookingPrice.sort()


mail(BookingPrice[0],BookingDate[sort_index_booking[0]], ExpediaPrice[0], ExpediaDate[sort_index_expedia[0]])

print("Cheapest Price from Expedia is", ExpediaPrice[0])
print("Cheapest Date from Expedia is", ExpediaDate[sort_index_expedia[0]])

print("Cheapest Price from Booking.com is", BookingPrice[0])
print("Cheapest Date from Booking.com is", BookingDate[sort_index_booking[0]])
```

## Conclusion

In conclusion, developing a hotel price monitoring system with Python has demonstrated the language's vast capabilities. 

By harnessing web scraping, data analysis, and visualization, we've created an intelligent and user-friendly system. 

This project serves as a stepping stone, inspiring further innovation with Python. 

So, let this experience be a catalyst for your own Python adventures, as you tackle new challenges and craft ingenious solutions. 

The world awaits your creative touch, and Python is the perfect companion for the journey ahead.