Table of contents

How to Handle Date and Time Pickers in Puppeteer?

Date and time pickers are common form elements that can be challenging to automate in web scraping and testing scenarios. Puppeteer provides several approaches to interact with these components, from simple HTML5 date inputs to complex custom date picker widgets. This guide covers comprehensive techniques for handling various types of date and time pickers effectively.

Understanding Date and Time Picker Types

Before diving into implementation, it's important to understand the different types of date and time pickers you might encounter:

HTML5 Native Pickers

  • <input type="date"> - Date picker
  • <input type="time"> - Time picker
  • <input type="datetime-local"> - Combined date and time picker
  • <input type="month"> - Month picker
  • <input type="week"> - Week picker

Custom JavaScript Pickers

  • jQuery UI Datepicker
  • Bootstrap Datepicker
  • Flatpickr
  • React Date Picker
  • Angular Material Date Picker

Method 1: Direct Value Setting for HTML5 Inputs

The simplest approach for HTML5 date and time inputs is to set the value directly:

const puppeteer = require('puppeteer');

async function handleNativeDatePicker() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/form');

    // Handle date input
    await page.type('#date-input', '2024-12-25');

    // Handle time input
    await page.type('#time-input', '14:30');

    // Handle datetime-local input
    await page.type('#datetime-input', '2024-12-25T14:30');

    // Handle month input
    await page.type('#month-input', '2024-12');

    // Handle week input
    await page.type('#week-input', '2024-W52');

    await browser.close();
}

Method 2: Using JavaScript Evaluation

For more complex scenarios or when direct typing doesn't work, you can use JavaScript evaluation:

async function setDateWithEvaluation() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/form');

    // Set date using evaluate
    await page.evaluate(() => {
        document.querySelector('#date-input').value = '2024-12-25';
        document.querySelector('#date-input').dispatchEvent(new Event('change'));
    });

    // Set time with custom format
    await page.evaluate(() => {
        const timeInput = document.querySelector('#time-input');
        timeInput.value = '14:30';
        timeInput.dispatchEvent(new Event('input'));
        timeInput.dispatchEvent(new Event('change'));
    });

    await browser.close();
}

Method 3: Handling Custom Date Picker Widgets

Custom date pickers often require more sophisticated interaction patterns:

async function handleCustomDatePicker() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/custom-datepicker');

    // Wait for the date picker to be available
    await page.waitForSelector('.datepicker-input');

    // Click to open the date picker
    await page.click('.datepicker-input');

    // Wait for the calendar to appear
    await page.waitForSelector('.datepicker-calendar');

    // Navigate to the desired month/year
    await page.click('.datepicker-next-month'); // Navigate months

    // Select a specific date
    await page.click('[data-date="2024-12-25"]');

    // Alternative: use keyboard navigation
    await page.keyboard.press('ArrowRight'); // Navigate days
    await page.keyboard.press('Enter'); // Select date

    await browser.close();
}

Method 4: Advanced Custom Picker Handling

For complex pickers like jQuery UI Datepicker or Bootstrap Datepicker:

async function handlejQueryDatePicker() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/jquery-datepicker');

    // Method 1: Direct jQuery manipulation
    await page.evaluate(() => {
        $('#datepicker').datepicker('setDate', '12/25/2024');
        $('#datepicker').trigger('change');
    });

    // Method 2: Simulating user interaction
    await page.click('#datepicker');
    await page.waitForSelector('.ui-datepicker');

    // Navigate to the correct month/year
    const targetMonth = 11; // December (0-indexed)
    const targetYear = 2024;

    await page.evaluate((month, year) => {
        $('.ui-datepicker').datepicker('setDate', new Date(year, month, 25));
    }, targetMonth, targetYear);

    await browser.close();
}

Method 5: Handling Time Pickers

Time pickers often have unique interaction patterns:

async function handleTimePicker() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/timepicker');

    // For custom time pickers with dropdowns
    await page.click('.time-picker-hours');
    await page.click('[data-hour="14"]');

    await page.click('.time-picker-minutes');
    await page.click('[data-minute="30"]');

    // For time pickers with scroll wheels
    await page.evaluate(() => {
        const hoursWheel = document.querySelector('.hours-wheel');
        const minutesWheel = document.querySelector('.minutes-wheel');

        // Simulate scroll to select time
        hoursWheel.scrollTop = 14 * 20; // Assuming 20px per hour
        minutesWheel.scrollTop = 30 * 20; // Assuming 20px per minute

        // Trigger change events
        hoursWheel.dispatchEvent(new Event('change'));
        minutesWheel.dispatchEvent(new Event('change'));
    });

    await browser.close();
}

Method 6: Using Page.$eval for Complex Scenarios

When dealing with shadow DOM or complex widget structures:

async function handleComplexDatePicker() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/complex-picker');

    // Handle date picker within shadow DOM
    await page.evaluate(() => {
        const datePicker = document.querySelector('custom-date-picker');
        const shadowRoot = datePicker.shadowRoot;
        const input = shadowRoot.querySelector('input');

        input.value = '2024-12-25';
        input.dispatchEvent(new Event('change', { bubbles: true }));
    });

    // Handle React-based date pickers
    await page.evaluate(() => {
        const reactDatePicker = document.querySelector('[data-testid="date-picker"]');

        // Trigger React's synthetic events
        const nativeInputValueSetter = Object.getOwnPropertyDescriptor(
            window.HTMLInputElement.prototype,
            'value'
        ).set;

        nativeInputValueSetter.call(reactDatePicker, '12/25/2024');

        const event = new Event('input', { bubbles: true });
        reactDatePicker.dispatchEvent(event);
    });

    await browser.close();
}

Method 7: Handling Multiple Date Ranges

For date range pickers that require selecting start and end dates:

async function handleDateRangePicker() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    await page.goto('https://example.com/date-range-picker');

    // Click to open date range picker
    await page.click('.daterange-picker');

    // Select start date
    await page.click('[data-date="2024-12-01"]');

    // Select end date
    await page.click('[data-date="2024-12-25"]');

    // Apply the selection
    await page.click('.apply-button');

    // Alternative: direct input method
    await page.type('#start-date', '2024-12-01');
    await page.type('#end-date', '2024-12-25');

    await browser.close();
}

Method 8: Error Handling and Validation

Robust date picker handling should include error handling and validation:

async function handleDatePickerWithValidation() {
    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();

    try {
        await page.goto('https://example.com/form');

        // Wait for date picker to be available
        await page.waitForSelector('#date-input', { timeout: 5000 });

        // Attempt to set date
        await page.type('#date-input', '2024-12-25');

        // Verify the date was set correctly
        const dateValue = await page.$eval('#date-input', el => el.value);
        console.log('Date set to:', dateValue);

        // Check for validation errors
        const errorMessage = await page.$('.error-message');
        if (errorMessage) {
            const errorText = await page.evaluate(el => el.textContent, errorMessage);
            console.log('Validation error:', errorText);
        }

    } catch (error) {
        console.log('Error handling date picker:', error);

        // Fallback method
        await page.evaluate(() => {
            const input = document.querySelector('#date-input');
            if (input) {
                input.value = '2024-12-25';
                input.dispatchEvent(new Event('change'));
            }
        });
    } finally {
        await browser.close();
    }
}

Best Practices and Tips

1. Always Wait for Elements

await page.waitForSelector('.datepicker-input');
await page.waitForSelector('.datepicker-calendar', { visible: true });

2. Handle Different Date Formats

function formatDate(date, format) {
    const d = new Date(date);
    switch(format) {
        case 'MM/DD/YYYY':
            return `${(d.getMonth() + 1).toString().padStart(2, '0')}/${d.getDate().toString().padStart(2, '0')}/${d.getFullYear()}`;
        case 'YYYY-MM-DD':
            return `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
        default:
            return date;
    }
}

3. Use Explicit Waits

await page.waitForFunction(() => {
    const picker = document.querySelector('.datepicker');
    return picker && picker.style.display !== 'none';
});

4. Clear Existing Values

await page.evaluate(() => {
    document.querySelector('#date-input').value = '';
});
await page.type('#date-input', '2024-12-25');

Common Issues and Solutions

Issue 1: Date Picker Not Opening

Solution: Ensure proper waiting and try different trigger methods:

await page.click('#date-input');
await page.focus('#date-input');
await page.keyboard.press('Enter');

Issue 2: Custom Events Not Triggering

Solution: Dispatch multiple event types:

await page.evaluate(() => {
    const input = document.querySelector('#date-input');
    input.dispatchEvent(new Event('input'));
    input.dispatchEvent(new Event('change'));
    input.dispatchEvent(new Event('blur'));
});

Issue 3: Date Format Mismatch

Solution: Always check the expected format and convert accordingly:

const expectedFormat = await page.evaluate(() => {
    return document.querySelector('#date-input').getAttribute('data-format');
});

Integration with Web Scraping APIs

For developers working with web scraping APIs, handling date and time pickers is crucial for comprehensive data extraction. When building applications that need to interact with date-sensitive forms, consider using automated form submission techniques to ensure reliable data collection.

Additionally, when dealing with complex interactive elements like date pickers, implementing proper timeout handling strategies becomes essential for robust automation scripts.

Conclusion

Handling date and time pickers in Puppeteer requires understanding the specific implementation of each picker type. From simple HTML5 inputs to complex custom widgets, the key is to identify the picker type and choose the appropriate interaction method. Always implement proper error handling, use explicit waits, and validate the results to ensure reliable automation.

Remember to test your implementation across different browsers and picker libraries, as behavior can vary significantly between implementations. With these techniques, you'll be able to handle virtually any date and time picker scenario in your Puppeteer automation scripts.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon