const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); async function searchSiblu() { const browser = await chromium.launch({ headless: true }); const context = await browser.newContext({ viewport: { width: 1920, height: 1080 }, userAgent: 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }); const page = await context.newPage(); const screenshotDir = path.join(process.env.HOME, 'holiday-planning', 'price-evidence'); const results = { searchDate: new Date().toISOString(), park: 'Domaine de Kerlann', parkId: 22, dates: { checkIn: '2026-07-18', checkOut: '2026-08-02', nights: 14 }, guests: { adults: 2, children: 1, childAge: 6 }, screenshots: [], status: 'in_progress' }; try { console.log('šŸ” Navigating to Siblu park page...'); await page.goto('https://siblu.co.uk/camping/france/west-coast/brittany/domaine-de-kerlann', { waitUntil: 'networkidle', timeout: 60000 }); // Handle cookie consent await page.waitForTimeout(2000); await page.evaluate(() => { const agreeBtn = document.getElementById('didomi-notice-agree-button'); if (agreeBtn) agreeBtn.click(); }); await page.waitForTimeout(1500); await page.screenshot({ path: path.join(screenshotDir, 'siblu-01-park-page.png'), fullPage: false }); results.screenshots.push('siblu-01-park-page.png'); console.log('āœ… Park page loaded'); // Fill in the booking form console.log('šŸ“… Filling booking form with dates 18 July - 2 August 2026...'); // Click on the arrival input to open the date picker const arrivalInput = await page.waitForSelector('#edit-arrival-beautify', { timeout: 10000 }); await arrivalInput.click(); await page.waitForTimeout(1000); // Navigate to July 2026 using flatpickr navigation // First, keep clicking next month until we reach July 2026 for (let i = 0; i < 16; i++) { // We need to go from March 2026 to July 2026 = 4 months const currentMonth = await page.textContent('.flatpickr-current-month .cur-month'); console.log(`Current month: ${currentMonth}`); if (currentMonth.includes('July') && currentMonth.includes('2026')) { break; } // Click next month button await page.click('.flatpickr-next-month'); await page.waitForTimeout(300); } await page.screenshot({ path: path.join(screenshotDir, 'siblu-02-date-picker.png'), fullPage: false }); results.screenshots.push('siblu-02-date-picker.png'); // Select July 18 console.log('Selecting July 18, 2026...'); await page.evaluate(() => { const days = document.querySelectorAll('.flatpickr-day'); for (const day of days) { if (day.getAttribute('aria-label') === 'July 18, 2026') { day.click(); return true; } } return false; }); await page.waitForTimeout(1000); // Now select August 2 for departure // Navigate to August if needed const currentMonth2 = await page.textContent('.flatpickr-current-month .cur-month'); if (!currentMonth2.includes('August')) { await page.click('.flatpickr-next-month'); await page.waitForTimeout(300); } console.log('Selecting August 2, 2026...'); await page.evaluate(() => { const days = document.querySelectorAll('.flatpickr-day'); for (const day of days) { if (day.getAttribute('aria-label') === 'August 2, 2026') { day.click(); return true; } } return false; }); await page.waitForTimeout(1000); await page.screenshot({ path: path.join(screenshotDir, 'siblu-03-dates-selected.png'), fullPage: false }); results.screenshots.push('siblu-03-dates-selected.png'); console.log('āœ… Dates selected'); // Click "See prices" button console.log('šŸ” Clicking "See prices"...'); const seePricesBtn = await page.waitForSelector('#edit-submit', { timeout: 10000 }); await seePricesBtn.click(); // Wait for navigation or results await page.waitForTimeout(5000); await page.screenshot({ path: path.join(screenshotDir, 'siblu-04-after-submit.png'), fullPage: true }); results.screenshots.push('siblu-04-after-submit.png'); console.log('āœ… Form submitted, current URL:', page.url()); // Check if we got redirected to checkout if (page.url().includes('checkout')) { console.log('šŸ“¦ Redirected to checkout page'); // Wait for prices to load await page.waitForTimeout(3000); await page.screenshot({ path: path.join(screenshotDir, 'siblu-05-checkout-page.png'), fullPage: true }); results.screenshots.push('siblu-05-checkout-page.png'); // Extract price information const pageText = await page.textContent('body'); const priceMatches = pageText.match(/Ā£[\d,]+\.?\d*/g); if (priceMatches) { results.pricesFound = [...new Set(priceMatches)]; console.log('šŸ’° Found prices:', results.pricesFound); } // Look for accommodation cards/options const accommodations = await page.evaluate(() => { const accs = []; document.querySelectorAll('[class*="accommodation"], [class*="mobile-home"], [class*="lodg"]').forEach(el => { const text = el.textContent.trim(); const priceMatch = text.match(/Ā£[\d,]+/); if (priceMatch) { accs.push({ text: text.substring(0, 200), price: priceMatch[0] }); } }); return accs; }); results.accommodations = accommodations; // Save the HTML for analysis const html = await page.content(); fs.writeFileSync(path.join(screenshotDir, 'siblu-checkout-page.html'), html); } results.finalUrl = page.url(); results.status = 'completed'; } catch (error) { console.error('āŒ Error:', error.message); results.error = error.message; results.stack = error.stack; await page.screenshot({ path: path.join(screenshotDir, 'siblu-error.png'), fullPage: true }); results.screenshots.push('siblu-error.png'); } await browser.close(); const resultsPath = path.join(process.env.HOME, 'holiday-planning', 'prices', 'siblu-domaine-de-kerlann.json'); fs.writeFileSync(resultsPath, JSON.stringify(results, null, 2)); console.log(`\nšŸ“ Results saved to: ${resultsPath}`); return results; } searchSiblu().catch(console.error);