1

I'm trying to receive a notification when a booking website shows that there is a new appointment available in the near future (eg. through a cancellation). The site in question is booksy.com.

I have written a Puppeteer script which will navigate to the page and click a button which will then open a popup displaying text about when the next available appointment is. The script works for that.

My next step is to get the scrip to actually read the contents of the popup. Which has been an issue, as it is just trying to read the original page prior to the popup opening.

const puppeteer = require('puppeteer');

(async () => {
  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();
  await page.goto('https://booksy.com/en-gb/45005_gents-of-richmond_barber_311817_london#ba_s=sgr_1');

  await page.waitForSelector('button[data-testid="service-button"]');
  const button = await page.$('button[data-testid="service-button"]');
  await button.click();

})();

I think if I could read the page, I could extract the month and date displayed, and perhaps evaluate that output against the current date and determine if it is in a timeframe such as the next 7 days. Sending me a notification if it is within that period.

What I'm asking is simply how I can actually evaluate the contents popup, getting it's month and/or date as an output. Thanks!

Quirkless
  • 55
  • 1
  • 5

1 Answers1

0

The booking modal is in a frame, so you can use .contentFrame() to access it and call methods on it like a page object:

const puppeteer = require("puppeteer"); // ^19.7.5

const url = "<Your URL>";

let browser;
(async () => {
  browser = await puppeteer.launch();
  const [page] = await browser.pages();
  await page.goto(url, {waitUntil: "domcontentloaded"});
  const btn = await page.waitForSelector(
    'button[data-testid="service-button"]'
  );
  await btn.click();
  const frameEl = await page.waitForSelector(
    '[data-testid="booking-widget"]'
  );
  const frame = await frameEl.contentFrame();
  await frame.waitForSelector(".chip div");
  const dates = await frame.$$eval(".chip", els =>
    Object.fromEntries(
      els
        .map(e =>
          [...e.querySelectorAll("div")].map(e => e.textContent)
        )
        .filter(Boolean)
    )
  );
  console.log(dates);
})()
  .catch(err => console.error(err))
  .finally(() => browser?.close());

I'm not entirely sure what data you want, but this gives you the week of dates. I'm hoping you can take it from here.

A few tips:

  • You usually don't have to re-select after waitForSelector, which returns the element it finds.
  • After you get the script working, consider blocking resources that aren't necessary to the data you need. This is a slow page.
  • The data you want is probably in a network response you can intercept, avoiding having to deal with the frame. But if you want to take an action on that modal, the DOM approach shown above is worth seeing anyway.
ggorlen
  • 44,755
  • 7
  • 76
  • 106