🟡 Web Automation with Selenium: Building a Bot to Book COVID-19 Vaccine Appointments

Building an Automated Appointment Booking System

Objective

Create a robust automated appointment booking system using Selenium WebDriver and software engineering best practices. This project focuses on developing a maintainable, scalable web automation solution that can handle multiple appointment booking scenarios while implementing proper error handling, logging, and monitoring mechanisms.


Learning Outcomes

By completing this project, you will:

  • Master web automation using Selenium WebDriver.
  • Implement design patterns for maintainable automation code.
  • Develop robust error handling and recovery mechanisms.
  • Create comprehensive logging and monitoring systems.
  • Build configurable and scalable automation solutions.
  • Practice software testing and quality assurance.

Prerequisites and Theoretical Foundations

1. Programming Skills

  • Python: Strong understanding of OOP principles
  • Software Design: Knowledge of design patterns
  • Testing: Understanding of test automation principles
  • Version Control: Git proficiency

2. Web Technologies

  • HTML/CSS: Understanding of web page structure
  • JavaScript: Basic knowledge for handling dynamic content
  • DOM: Understanding of document object model
  • Web APIs: RESTful services concepts

3. Automation Concepts

  • Selenium WebDriver: Core concepts and best practices
  • Page Object Model: Design pattern for web automation
  • Wait Strategies: Handling dynamic web elements
  • Browser Automation: Cross-browser testing concepts

Tools Required

  • Programming Language: Python 3.7+
  • Libraries:
    • Selenium: (pip install selenium)
    • WebDriver Manager: (pip install webdriver-manager)
    • Loguru: For logging (pip install loguru)
    • PyYAML: For configuration (pip install pyyaml)
    • pytest: For testing (pip install pytest)
  • Development Tools:
    • VS Code or PyCharm
    • Git for version control
    • Docker for containerization
  • Browsers and WebDrivers:
    • Chrome/Firefox with respective WebDrivers

Project Structure

appointment-booker/
│
├── src/
│   ├── page_objects/
│   │   ├── __init__.py
│   │   ├── base_page.py
│   │   ├── login_page.py
│   │   └── booking_page.py
│   ├── core/
│   │   ├── __init__.py
│   │   ├── driver_factory.py
│   │   ├── config_manager.py
│   │   └── logger.py
│   └── utils/
│       ├── __init__.py
│       ├── wait_utils.py
│       └── element_utils.py
├── tests/
│   ├── __init__.py
│   ├── conftest.py
│   └── test_booking.py
├── config/
│   └── config.yaml
├── logs/
├── requirements.txt
└── README.md

Steps and Tasks

1. Setting Up Project Infrastructure

Tasks:

  • Initialize Project Structure
  • Set Up Version Control
  • Configure Development Environment

Implementation:

# src/core/config_manager.py
import yaml
from dataclasses import dataclass

@dataclass
class AppConfig:
    base_url: str
    browser: str
    implicit_wait: int
    explicit_wait: int
    retry_attempts: int

class ConfigManager:
    def __init__(self, config_path: str):
        with open(config_path, 'r') as file:
            self._config = yaml.safe_load(file)
    
    def get_app_config(self) -> AppConfig:
        return AppConfig(**self._config['app'])

2. Implementing Core Framework Components

Tasks:

  • Create WebDriver Factory
  • Implement Base Page Object
  • Set Up Logging System

Implementation:

# src/core/driver_factory.py
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager

class WebDriverFactory:
    @staticmethod
    def create_driver(browser: str = 'chrome'):
        if browser.lower() == 'chrome':
            options = webdriver.ChromeOptions()
            options.add_argument('--start-maximized')
            service = Service(ChromeDriverManager().install())
            return webdriver.Chrome(service=service, options=options)
        # Add support for other browsers as needed
        raise ValueError(f"Unsupported browser: {browser}")

# src/page_objects/base_page.py
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

class BasePage:
    def __init__(self, driver, config):
        self.driver = driver
        self.config = config
        self.wait = WebDriverWait(driver, config.explicit_wait)
    
    def find_element(self, locator):
        return self.wait.until(EC.presence_of_element_located(locator))
    
    def click_element(self, locator):
        element = self.find_element(locator)
        element.click()

3. Building Page Objects

Tasks:

  • Create Login Page Object
  • Implement Booking Page Object
  • Add Navigation Methods

Implementation:

# src/page_objects/login_page.py
from selenium.webdriver.common.by import By
from .base_page import BasePage

class LoginPage(BasePage):
    # Locators
    USERNAME_FIELD = (By.ID, "username")
    PASSWORD_FIELD = (By.ID, "password")
    LOGIN_BUTTON = (By.ID, "login-btn")
    
    def login(self, username: str, password: str):
        self.find_element(self.USERNAME_FIELD).send_keys(username)
        self.find_element(self.PASSWORD_FIELD).send_keys(password)
        self.click_element(self.LOGIN_BUTTON)

# src/page_objects/booking_page.py
class BookingPage(BasePage):
    # Locators
    DATE_PICKER = (By.ID, "date-picker")
    TIME_SLOTS = (By.CLASS_NAME, "time-slot")
    CONFIRM_BUTTON = (By.ID, "confirm-booking")
    
    def select_date(self, date: str):
        date_picker = self.find_element(self.DATE_PICKER)
        date_picker.clear()
        date_picker.send_keys(date)
    
    def get_available_slots(self):
        slots = self.driver.find_elements(*self.TIME_SLOTS)
        return [slot.text for slot in slots if "available" in slot.get_attribute("class")]

4. Implementing Error Handling and Recovery

Tasks:

  • Create Custom Exceptions
  • Implement Retry Mechanism
  • Add Error Recovery Logic

Implementation:

# src/utils/retry_handler.py
from functools import wraps
from time import sleep
from loguru import logger

class BookingException(Exception):
    pass

def retry_on_failure(retries=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    logger.warning(f"Attempt {attempt + 1} failed: {str(e)}")
                    if attempt == retries - 1:
                        raise BookingException(f"Failed after {retries} attempts: {str(e)}")
                    sleep(delay)
            return None
        return wrapper
    return decorator

5. Adding Logging and Monitoring

Tasks:

  • Configure Logging System
  • Implement Performance Monitoring
  • Add Audit Trail

Implementation:

# src/core/logger.py
from loguru import logger
import sys
from pathlib import Path

class LogManager:
    def __init__(self, log_path: Path):
        self.log_path = log_path
        self._configure_logger()
    
    def _configure_logger(self):
        logger.remove()  # Remove default handler
        
        # Add file handler
        logger.add(
            self.log_path / "app.log",
            rotation="1 day",
            retention="1 week",
            level="INFO"
        )
        
        # Add console handler
        logger.add(
            sys.stdout,
            colorize=True,
            format="<green>{time}</green> <level>{message}</level>",
            level="INFO"
        )

6. Creating Test Suite

Tasks:

  • Write Unit Tests
  • Implement Integration Tests
  • Create Test Data Fixtures

Implementation:

# tests/test_booking.py
import pytest
from selenium.webdriver.common.by import By
from src.page_objects.booking_page import BookingPage

def test_booking_available_slot(driver, config):
    booking_page = BookingPage(driver, config)
    booking_page.navigate_to_booking()
    
    # Select date
    booking_page.select_date("2024-03-15")
    
    # Get available slots
    slots = booking_page.get_available_slots()
    assert len(slots) > 0, "No available slots found"
    
    # Book first available slot
    booking_page.book_slot(slots[0])
    
    # Verify booking confirmation
    confirmation = booking_page.get_confirmation_message()
    assert "successfully booked" in confirmation.lower()

7. Docker Integration

Tasks:

  • Create Dockerfile
  • Set Up Docker Compose
  • Configure Container Networking

Implementation:

# Dockerfile
FROM python:3.9-slim

# Install Chrome and Chrome WebDriver
RUN apt-get update && apt-get install -y \
    chromium \
    chromium-driver

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "-m", "pytest", "tests/"]

Further Enhancements

  • API Integration:

    • Add REST API support
    • Implement webhook notifications
  • Scheduling Features:

    • Add cron job support
    • Implement booking queue system
  • Reporting:

    • Generate HTML reports
    • Create booking analytics
  • Security:

    • Add credential encryption
    • Implement rate limiting

Conclusion

This project demonstrates:

  • Robust Web Automation: Using Selenium with best practices
  • Software Architecture: Implementing design patterns
  • Quality Assurance: Through comprehensive testing
  • Operational Excellence: With logging and monitoring
  • Scalability: Through containerization and configuration

The system serves as a foundation for building reliable and maintainable web automation solutions.