javascriptcss-selectorspuppeteer

How do I make Puppeteer only click selector with a set "status"?


I am trying to make a bot to help me buy tickets but, as the picture shows, only a few seats are available.

I have a problem to work out how to make Puppeteer only click the available seats.

In the picture below, there are a lot of sold seats and some available ones. In the developer tools to the right side in the picture I can easily separate the sold seats from the available ones by looking at the data-status="available" part.

I have managed to make the bot click every seat, but not to only click the green ones. If possible, I also only want it to click a couple of green ones, and not all of them, 3 to 4 would be perfect.

Image of available seats: due to low reputation I have to link the image

The code I have for clicking the seats looks like this (and keeps going until it has clicked all the seats):

    await page.waitForSelector("#arena > div > div > div > div > div > div > div:nth-child(1)"
    await page.click ("#arena > div > div > div > div > div > div > div:nth-child(1)"), elem => elem.click();
    await delay(10);
    await page.click ("#arena > div > div > div > div > div > div > div:nth-child(2)"), elem => elem.click();
    await delay(10);
    await page.click ("#arena > div > div > div > div > div > div > div:nth-child(3)"), elem => elem.click();
    await delay(10);
    await page.click ("#arena > div > div > div > div > div > div > div:nth-child(4)"), elem => elem.click();
    await delay(10);
    await page.click ("#arena > div > div > div > div > div > div > div:nth-child(5)"), elem => elem.click();

I want it to click the seats with the value data-status="available"

I added await delay because there is a pop up that fades in when you have to "confirm seat" which I will be implementing later, as I feel that should be fairly easy.

How do I make Puppeteer only click available seats?


Solution

  • Try selecting those seats by the data attribute:

    await page.$$eval(
      '.tc-section--seat[data-status="available"]',
      els => els.forEach(e => e.click())
    );
    

    Maybe use #arena .tc-section--seat[data-status="available"] if there are other sections that you need to disambiguate.

    Alternately, if you want to use trusted Puppeteer clicks:

    const seatEls = await page.$$('.tc-section--seat[data-status="available"]');
    
    for (const el of seatEls) {
      await el.click();
    }
    

    I suggest steering clear of those browser generated selectors. They're simultaneously too specific and vague at the same time (not using a clear-cut class or data attribute, instead using a giant rigidly-specified tree of plain tag names).

    Disclosure: I'm the author of the linked blog post.