Reputation: 4443
Working on a script that would use puppeteer to book tee times when they become available. If I have a specified day that I know I want to book, I was wondering if there's a good way to select that date in datepicker (all of the dates have a class "day" but aren't identifiable individually). This is datepicker without an input, on a site where I don't control the datepicker. I just want to be able to fill out the form and make the appropriate selections but all of the dates have the same selector. I'm attaching a picture of the datepicker. What is the best way to go about selecting a date that's 7 days in advance?
Upvotes: 1
Views: 744
Reputation: 8851
You are able to collect the content of the calendar with page.$eval
and page.$$eval
methods:
const calMonthYear = await page.$eval('.calendar-monthname', month => month.innerText)
// September 2020
const calDays = await page.$$eval('.calendar-grid > ul > li', days => days.map(d => d.innerText))
// ["30", "31", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "1", "2", "3"]
Note: in the final example I declare them with let
due to they need to be redeclared once we have to step to the next month on date selection.
Then if you concat the dates you can make every calendar day element a valid JavaScript Date object, e.g.:
Date.parse(`${calDays[10]} ${calMonthYear}`) // 9 September 2020
// 1599602400000
The current day (today) always has a specific class name, e.g.: .selected
, we can evaluate its date with puppeteer (let's assume this is the valid "now" and not Date.now()
)
const calToday = await page.$eval('.selected', day => day.innerText)
// 9
const todayIndex = calDays.indexOf(calToday)
// 10
const todayEpoch = Date.parse(`${calDays[todayIndex]} ${calMonthYear}`) // 9 September 2020
// 1599602400000
We can create a date desired to be selected in Epoch format (it should be Date.parse()
-ed):
let today = new Date(todayEpoch)
let sevenDaysLater = new Date()
sevenDaysLater.setDate(today.getDate() + 7)
sevenDaysLater.setHours(0,0,0,0)
// 1600207200000 (Wed Sep 16 2020 00:00:00 GMT+0200 (Central European Summer Time))
And finally you should compose an iteration to select the desired 7 days later element, something like this:
[...]
let calendarGridItemCount = await page.$$eval('.calendar-grid > ul > li', el => el.length)
let calMonthYear = await page.$eval('.calendar-monthname', month => month.innerText)
let calDays = await page.$$eval('.calendar-grid > ul > li', days => days.map(d => d.innerText))
const wantedDate = Date.parse(sevenDaysLater)
for (let i = 0; i < calendarGridItemCount; i++) {
let examinedCalendarGridItem = Date.parse(`${calDays[i]} ${calMonthYear}`)
if (examinedCalendarGridItem == wantedDate) {
const dayFound = (await page.$$('.calendar-grid > ul > li'))[i]
await dayFound.click()
break
} else if (examinedCalendarGridItem !== wantedDate && i === calendarGridItemCount - 1) {
await page.click('.calendar-next')
calendarGridItemCount = await page.$$eval('.calendar-grid > ul > li', el => el.length)
calMonthYear = await page.$eval('.calendar-monthname', month => month.innerText)
calDays = await page.$$eval('.calendar-grid > ul > li', days => days.map(d => d.innerText))
i = 0
continue
}
}
.calendar-next
button);calDays
array with keeping their indexes (the indexes are needed in the iteration to identify the selectable dates, slicing the past dates would mess up their order).Upvotes: 1