2

I'am currently web scraping one page with puppeteer. I am trying to make something which can speed up my work.

My HTML Markup looks something like this

<div class="inner-wrapper" style="">
<div class="style-001">
    <ul role="listbox" aria-multiselectable="true" class="style-002">
    <li role="option" aria-selected="false" class="style-003">
        <span class="style-004">First Option</span>
    </li>
    <li role="option" aria-selected="false" class="style-003">
        <span class="style-004">Second Option</span>
    </li>
    <li role="option" aria-selected="false" class="style-003">
        <span class="style-004">Third Option</span>
    </li>      
    </ul>
</div>

I was trying to select specific 'li' based on span's text. This page is dynamic so sometimes 'Third Option' will have index [3] and sometimes other one. It have to be selected just by span's text because It won't work in other situations. I can't use class because this website uses same classes for every 'li'.

I did research on google and stackoverflow and didn't find working solution. I tried selecting by xpath, js selector and more. And even I tried something like this:

const [link] = await page.$x('//div[2]/div/div/section/div[2]/div/div/div/ul/li[2]/span[contains(text(), "First Option")]'); 
await link.click();

or

let selectOption = await page.waitForXPath(`//div[2]/div/div/section/div[2]/div/div/div/ul/li[contains(text(),'First Option')]`);
await selectOption.click();

If someone can help me, I will huge appreciate.

@EDIT If it is important clicking on any option this website changes aria-selected="false" to "true". Maybe it will help in any way?

1 Answer 1

2

You can try and use page.evaluate and than use querySelectorAll and filter the li by text than use a forEach to click on the il with the specific text.

await page.evaluate(() => {
  Array.from(document.querySelectorAll('li')).filter(li => {
    return li.innerText == 'First Option' // filter il for specific text
  }).forEach(element => {
    if (element) element.click(); // click on il with specific text
  });
});

If the first one does not work you can try.

await page.evaluate(() => {
  Array.from(document.querySelectorAll('div > div > ul > li')).filter(li => {
    return li.innerText == 'First Option' // filter il for specific text
  }).forEach(element => {
    if (element) element.click(); // click on il with specific text
  });
});

You could also give this a try and i think this would be the best way todo it.

await page.evaluate(() => {
  const elements = [...document.querySelectorAll('div > div > ul > li')];
  const targetElement = elements.find(e => e.innerText == 'First Option');
  if (targetElement) targetElement.click();
});

or

await page.evaluate(() => {
  const elements = [...document.querySelectorAll('li')];
  const targetElement = elements.find(e => e.innerText == 'First Option');
  if (targetElement) targetElement.click();
});
Sign up to request clarification or add additional context in comments.

4 Comments

OMG, you are the best, man. I am trying to find any solution for week and you did it withing hour. I didn't try every solution, but third works fine. I would like to have your brain :d, love you xoxo
Haha I'm happy i could help you! And yeah the third solution is want i would use also.
Did the API change? I'm not seeing a click method for element. InnerText isn't resolving either.
@chaostheory I don't think so, but other people in this issue had similar problems. I found that a combination of await page.waitForSelector('.someSelector', 300); and await page.$eval('.someSelector', ((el) => el.click())); worked for my use case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.