Asgeir
Asgeir

Reputation: 677

Selecting second jQuery match when using click()

I'm experimenting with web scraping, but I've run into this minor issue. The website I want to scrape has 2 buttons, both with the same class. Using Puppeteer, I want to click the second button. Issue is, that I can't figure out how to select the second element when I have to do a string jQuery in the click function.

page.click('.ws-collapsable-block__heading')

The line above works great for clicking the first button, but as I said, I'm trying to click the second button. I've tried:

page.click('.ws-collapsable-block__heading:eq(1)')
page.click('.ws-collapsable-block__heading').eq(1)
page.click('.ws-collapsable-block__heading'.eq(1))
page.click('.ws-collapsable-block__heading'[1])
page.click('.ws-collapsable-block__heading')[1]

None of them work though.

My second solution was using a traditional jQuery DOM search like this:

document.querySelector('.ws-collapsable-block__heading')

but I can't access "document" outside a page evaluation, and I can't access page inside an evaluation.

Full script underneath:

const puppeteer = require('puppeteer')

async function get_info(code) {

    let url = 'https://joker.no/sok?query=' + code

    let browser = await puppeteer.launch()
    let page = await browser.newPage()

    await page.goto(url, { waitUntil: 'networkidle2' })

    let get_link = await page.evaluate(() => document.querySelector('.ws-product__title').getAttribute('href') )
    let product_name = await page.evaluate(() => document.querySelector('.ws-product__title').innerText );

    await page.goto('https://joker.no' + get_link)

    // This clicks the first button...
    page.click('.ws-collapsable-block__heading')

    await page.screenshot({path: 'x.png'})    
}

get_info('7311041013663')

Edit: I tried using nth like this

page.click('.ws-collapsable-block__heading:nth-child(2)')

but it gives this error

(node:5856) UnhandledPromiseRejectionWarning: Error: No node found for selector: .ws-collapsable-block__heading:nth-child(2)
    at assert (E:\Node\KaloriApp\node_modules\puppeteer\lib\helper.js:283:11)
    at DOMWorld.click (E:\Node\KaloriApp\node_modules\puppeteer\lib\DOMWorld.js:366:5)
    at process._tickCallback (internal/process/next_tick.js:68:7)
  -- ASYNC --
    at Frame.<anonymous> (E:\Node\KaloriApp\node_modules\puppeteer\lib\helper.js:111:15)
    at Page.click (E:\Node\KaloriApp\node_modules\puppeteer\lib\Page.js:1067:29)
    at get_info (E:\Node\KaloriApp\app.js:17:10)
    at process._tickCallback (internal/process/next_tick.js:68:7)
(node:5856) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:5856) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.

If I try document.querySelectorAll('.ws-collapsable-block__heading:nth-child(1)') on the website, I get a nodeList with size 3. I still have to do document.querySelectorAll('.ws-collapsable-block__heading:nth-child(1)')[1] to get the second element though, which I can't seem to do in the click function.

Upvotes: 0

Views: 1153

Answers (2)

Yevhen Laichenkov
Yevhen Laichenkov

Reputation: 8672

You can easily grab all the products with the page.$$ method and then click one of them. Don't forget to add await.

For instance:

const [ firstProduct, secondProduct, thirdProduct ] = await page.$$('.ws-panel');

await secondProduct.click(); // click the second button

Upvotes: 2

john Smith
john Smith

Reputation: 17906

Use nth-child selector

page.click('.ws-collapsable-block__heading:nth-child(2)')

Upvotes: 1

Related Questions