What Changed: - Added VERIFIED-PRICES.md with honest assessment - Added BUDGET-REALITY.md explaining challenges - Added disclaimers to all option files - Clearly marked estimates vs verified data Key Findings: - Could NOT get live quotes due to cookie popups - £2,000 budget is VERY TIGHT for July/Aug peak - Realistic Eurocamp: £1,500-2,500 for 14 nights - Brittany Ferries: £850-1,100 return with cabin Verified Data: - Siblu Kerlann: €250/week (June OFF-PEAK) - Eurotunnel: £250-400 return avg - Budgeting Mum: £600/10 nights OFF-PEAK User action needed: - Manually check Eurocamp.co.uk - Consider shorter duration - Consider gîte instead of mobile home
189 lines
6.5 KiB
JavaScript
189 lines
6.5 KiB
JavaScript
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);
|