develop price monitoring system of your own

How to Develop a Hotel Price Monitoring System Using Python

Hotel price tracking has become quite important for the travel industry. There are so many competitors in the market due to keeping track of all the individual OTAs has become quite difficult.

In this article, we are going to use python to create a simple hotel price-tracking script. We will track hotel prices for a range of dates and whatever date comes out cheaper we are going send ourselves an email with the best offer.

What do we need before writing the code?

We will use Python 3.x for this tutorial and I am assuming that you have already installed Python on your machine. The next step would be to create a dedicated folder for our project.

mkdir hotelpricetracker

Then you can create a python file inside this folder. I am naming the file as 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

We also need a hotel API that can pull fresh hotel prices from multiple OTAs in just one GET request. For that, we are going to use Makcorps Hotel API. You can contact us for access to the premium APIs.

Makcorps Home Page

Otherwise, you can just register for the trial pack.

What data are we going to search in hotel API?

Let’s say you want to visit Boston for two days but you want to find out what are the cheapest days. And you want to stay at The Lenox hotel. You have holidays from the 11th of March to the 16th of March and you want to find out which check-in date will be the cheapest.

So, you can check in on the 11th or 12th or 13th or 14th, or 15th of March and you want to book this hotel from either Expedia or Boooking.com.

So, we are going to get hotel prices from the API for these two OTAs and then compare them for all the dates.

After comparing the prices for all the dates we are going to send an email to ourselves with the cheapest date.

Let’s Start Tracking Hotel Prices

The first step is to import all the libraries that we just installed.

import requests

Now, we will make a GET request to the hotel API for all the dates one by one using a for loop.

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

Let me explain step-by-step what we have done over here.

  • We have declared some empty arrays and objects.
  • Then we are running a for loop five times because we have five days of holidays and we want to check prices for days falling between those dates.
  • Using requests we have made a GET request to the API.
  • Then we again ran a for loop to extract prices from each response. Here we are extracting prices of booking.com and expedia.com and then storing them in an object o.
  • At the end of the first for loop, list l will have all the prices and respective dates.

If you are wondering what the API response looks like then check this.

{
  "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
      }
    ],
    [
      
    ]
  ]
}

Now we have to create separate lists for both OTAs. The reason behind this is to sort prices in increasing order at a later stage.

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'])

Here we have created four separate arrays ExpediaPriceExpediaDateBookingPrice and BookingDate.

  1. ExpediaPrice will have integer values of price from Expedia.
  2. ExpediaDate will have dates of that respective price from Expedia.com.
  3. BookingPrice will have integer values of price from Booking.com.
  4. BookingDate will have dates of that respective price from Booking.com.

We have now the data but all we have to do is to sort the prices in increasing order so that we can determine which price is the cheapest and for which date this price is available.

We can sort ExpediaPrice and BookingPrice arrays using .sort() method.

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 NumpyIt 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()

Using .array() function we are inserting the target array list which needs to be sorted then using .argsort() numpy will provide you a list of indices in increasing order. This is also known as indirect sorting.

sort_index_expedia and sort_index_booking will have the original position of each price. Through this, we can now determine the date of the sorted price list array as well.

Once you print you will 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]])

The only thing which is left is to mail yourself the best offer for your holidays.

How to Mail?

For mailing, we are going to use smtplib library to send emails using our Gmail account. Again you don’t have to install it, it already comes with 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("[email protected]", "your_passowrd")
 SUBJECT = "Price Alert"
 message = 'From: [email protected] \nSubject: {}\n\n{}'.format(SUBJECT, attackMsg)
 server.sendmail("[email protected]", '[email protected]', message)

 server.quit()
 return True
  • The first line defines a function named mail that takes four arguments: bookingPricebookingDateexpediaPrice, and expediaDate.
  • The second step creates a string variable named attackMsg using triple quotes. The string contains placeholders ({}) for the four arguments of the function. The format method is used to substitute the placeholders with the actual values of the arguments.
  • The next four lines set up a connection to a Gmail SMTP server using the smtplib library. The ehlo and starttls methods are used to initiate a secure connection. The login method is used to authenticate the user with the SMTP server using their email address and password.
  • Two lines after this define the subject and body of the email message. The message variable contains a formatted string that includes the SUBJECT variable and the attackMsg variable.
  • The next line sends the email message using the sendmail method of the SMTP object. The email is sent from the email address specified in the first argument ([email protected]) to the email address specified in the second argument ([email protected]).
  • 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.

You will receive an email that will look like this.

Email That You Will Receive

Complete Code

Now, of course, you can use this code to track prices for a longer range of dates. Using this data you can keep a track of prices offered by your competitors also.

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("[email protected]", "your_passowrd")
 SUBJECT = "Price Alert"
 message = 'From: [email protected] \nSubject: {}\n\n{}'.format(SUBJECT, attackMsg)
 server.sendmail("[email protected]", '[email protected]', 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 this tutorial, you learned how to track multiple OTAs with just a simple hotel API. You can use this data for tracking the prices from multiple OTAs or you can show a snippet on your website just beside your own price. You can show that you offer a much lower price than your competitors.

Of course, there are many applications for this data. If you want to track a large number of hotels then I would advise you to use this API.

I hope you like this little tutorial and if you do then please do not forget to share it with your friends and on your social media.

Additional Resources

Here are a few additional resources that you may find helpful during your web scraping journey:

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *