How I Made a Reservation Bot With Selenium

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

            

Introduction

After I failed one too many times to get a competitive reservation, I decided enough was enough and to figure out how I can compete with all of the ticket-gouging bots out there. I ultimately settled on using Python and Selenium, since that's what I was most familiar with. In this blog post, I’ll walk you through the process of how I created a Python Selenium bot that automates the reservation process with the Kirby Cafe in Japan.

Understanding The Booking System

Most reservation systems are made up of components that allow the user to select the date, time, and package to reserve, as well as billing information upon confirmation.

Kirby Drawing

Often times for the more competitive tickets and reservations, reservations open at a specific date and time.

For the Kirby Cafe, the reservation system is a simple web form that first requires the user to acknowledge the terms and conditions, select the number of guests to reserve, then pick the date and time from a calendar grid, and submit contact details. Reservations are released on the 10th of every month at 10AM JST.

Knowing this information, I then made a gameplan to make my bot walk through the reservation process on my behalf.

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
                
            

Bot Architecture Overview

My bot is a Python script that uses the Selenium library to automate the reservation process. Selenium is a powerful tool that allows you to interact with web browsers in a programmatic way. It’s often used for testing web applications, but it’s also great for automating repetitive tasks like filling out forms or clicking buttons.

Here’s a high-level overview of how my bot works:

1. Wait for the reservation to open at 10AM JST of the month before the reservation date
2. Open the Kirby Cafe reservation page
3. Acknowledge the terms and conditions
4. Select the number of guests
5. Select the date and time
6. Fill out the contact form
7. Submit the reservation

I didn't end up coding the entire bot due to the reservation system being closed for the days I spent building this application, and only programmed up to Step 5. I also didnt want to boof the submission of any of my personal details, so the bot waits for me to submit my own information and complete the reservation after it opens the date and time I want.

Nonetheless, this bot worked great for what I needed and was able to get a reservation!

Requirements

Here’s what you’ll need to follow along with this tutorial:

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
              
            

Code Breakdown

Here’s a simplified version of the Python script that automates the reservation process:

Setting up the Web Driver

First, we need to set up the web driver. This is the tool that Selenium uses to interact with the web browser. We’ll use the Chrome WebDriver, but you can use any browser that Selenium supports. You’ll also need to install the Selenium library if you haven’t already.

From a new python file, we will be using selenium webdriver packages


from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.chrome.options import Options

Once we have our imports set, we are ready to build the driver that the bot will be using to load pages and make clicks on our behalf


#Statically assign website to begin the reservation process from
website = "https://kirbycafe-reserve.com/guest/tokyo/"

#Build the webdriver with the Chrome drivers and executable installation paths
service=webdriver.chrome.service.Service("C:\\Program Files\\chromedriver\\chromedriver.exe") #This is the directory where my Chrome Web Driver Binary is installed
chrome_options.binary_location = "C:\\Program Files\\chrome-win64\\chrome.exe" #This is the directory where my Chrome Browser Binary is installed

#Build driver options with Options import
chrome_options = Options()
chrome_options.add_argument("--enable-chrome-browser-cloud-management") #This allows us to use Chrome's development options and actually run the bot
chrome_options.add_experimental_option("detach", True) #This allows us to add manual edits to our reservations once the bot has finished its execution steps
chromedriver = "chromedriver" #Specify the type of driver we are using to Selenium

#Build the driver with the specified options
driver = webdriver.Chrome(service=service,options=chrome_options)

#Load the Reservation Website
driver.get(website)

The above information can be used as a base for building any bot with the drivers you specified. From here, you will have to customize the settings and pages pulled to your specific reservation.

Copying Element Paths With Browser Web Developer Tools

Once we have the driver set up, we can start copying the element paths of the web page we want to interact with. This is where the browser’s web developer tools come in handy. You can right-click on any element on the page and select “Inspect” to see the HTML and CSS that makes up the page. You can then right-click on the HTML and select “Copy” > “Copy XPath” to copy the element’s XPath to your clipboard.

If you are unfamiliar with Web Developer Tools, on most browsers you can press the Windows Key, the Shift key, and the I key at the same time to open developer tools. From there you can click the little arrow in the top left of that window and select any element and it will take you straight to that element's code.

Inspect Element

Now you can right click on that element, hover over Copy, and then select XPath to get what Selenium needs. For example, here’s how we can select the number of guests to reserve:

Inspect Element

#Select the number of guests
driver.find_element(By.XPATH, "//div[@class='v-input theme--light v-text-field v-text-field--filled v-text-field--is-booted v-text-field--enclosed v-select']").click()
driver.find_element(By.XPATH,"//div[contains(text(),'2名様')]").click()

Using this process, you can do some trial and error to figure out what elements are interactable.

────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
    

Putting it All Together

After a few hours of debugging the proper paths, I made the following bot to make a reservation for the Kirby Cafe


    from selenium import webdriver
    import time
    from selenium.webdriver.common.keys import Keys
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import Select
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.chrome.options import Options
    from selenium.common.exceptions import NoSuchElementException
    from selenium.common.exceptions import ElementClickInterceptedException
    from selenium.common.exceptions import ElementNotInteractableException
    
    def create_rez(day_of_month, num_of_guests):
    
        website = "https://kirbycafe-reserve.com/guest/tokyo/"

        service=webdriver.chrome.service.Service('chromedriver/chromedriver.exe')
        chrome_options = Options()
        chrome_options.binary_location = "C:\\Program Files\\chrome-win64\\chrome.exe"
        chrome_options.add_argument("--enable-chrome-browser-cloud-management")
        chrome_options.add_experimental_option("detach", True)
        chromedriver = "chromedriver"
        driver = webdriver.Chrome(service=service,options=chrome_options)
        driver.get(website)

        try:    
            # STEP 1 - Agree to terms and conditions
            element=WebDriverWait(driver,20).until(EC.element_to_be_clickable((By.XPATH, "//*[contains(text(),'上記の内容を確認しました')]")))
            element.click()
            driver.find_element(By.XPATH, "//*[contains(text(),'予約へ進む')]").click()
    
            #STEP 2 - ACK
            element=WebDriverWait(driver,20).until(EC.element_to_be_clickable((By.XPATH, "/html/body/div/div/div/div[1]/div/div/div[2]/button")))
            element.click()
    
            # STEP 3 - Select number of guests
            #NOTE: Change the '2名様' to whatever number of guests you want to reserve for. This is set to 2 guests.
            driver.find_element(By.XPATH, "//div[@class='v-input theme--light v-text-field v-text-field--filled v-text-field--is-booted v-text-field--enclosed v-select']").click()
            driver.find_element(By.XPATH,"//div[contains(text(),'2名様')]").click()
    
            #STEP 4 - Select day from calendar
            #NOTE: Change the '3月' to whatever month you want to reserve a day for -- the number is the day of the month 
            driver.find_element(By.XPATH, "//*[contains(text(), '3月')]").click()
            time.sleep(2)

            #STEP 5 - Select time + day in grid
            #NOTE: Copy the XPATH of the day you want to reserve and paste it in the driver.find_element(By.XPATH, "PASTE HERE").click() line. The code below will likely not work for what you want it to.
            driver.find_element(By.XPATH, "/html/body/div/div/div/div[3]/div[2]/div/div[1]/div[2]/div[2]/div[2]/table/tbody/tr[1]/td[21]/div/span").click()
            time.sleep(600)
    
        except NoSuchElementException:
            pass
        except ElementClickInterceptedException:
            pass
        except ElementNotInteractableException:
            pass

    #Invoke the Reservation on the 21st of March for 2 guests
    create_rez(21, 2)

Conclusion

Et voila. I set up a scheduled task and an alarm to wake up to do the reservation right on the hour and I was able to get the time and date I wanted. I did try this for a different site, but I was not able to get past the rate limit, so I advise changing the code to have the bot wait for the reservations to release instead.

Good luck in your future reservations!