最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Clicking a selector with Puppeteer - Stack Overflow

programmeradmin6浏览0评论

So I am having trouble clicking a login button on the nike website..

I am not sure why It keeps crashing, well because it can't find the selector I guess but I am not sure what I am doing wrong.

I would like to also say I am having some sort of memory leak before puppeteer crashes and sometimes it will even crash my macbook pletely if I don't cancel the process in time inside the console.

EDIT: This code also causes a memory leak whenever it crashes forcing me to have to hard reset my mac if I don't cancel the application fast enough.

Node Version: 14.4.0 Puppeteer Version: 5.2.1

Current code:

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false,
        defaultViewport: null,
        args: ['--start-maximized']
    })

    const page = await browser.newPage()
    await page.goto('/')

    const winner = await Promise.race([
        page.waitForSelector('[data-path="join or login"]'),
        page.waitForSelector('[data-path="sign in"]')
    ])

    await page.click(winner._remoteObject.description)
})()

I have also tried:

await page.click('button[data-var]="loginBtn"');

So I am having trouble clicking a login button on the nike website..

I am not sure why It keeps crashing, well because it can't find the selector I guess but I am not sure what I am doing wrong.

I would like to also say I am having some sort of memory leak before puppeteer crashes and sometimes it will even crash my macbook pletely if I don't cancel the process in time inside the console.

EDIT: This code also causes a memory leak whenever it crashes forcing me to have to hard reset my mac if I don't cancel the application fast enough.

Node Version: 14.4.0 Puppeteer Version: 5.2.1

Current code:

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false,
        defaultViewport: null,
        args: ['--start-maximized']
    })

    const page = await browser.newPage()
    await page.goto('https://www.nike./')

    const winner = await Promise.race([
        page.waitForSelector('[data-path="join or login"]'),
        page.waitForSelector('[data-path="sign in"]')
    ])

    await page.click(winner._remoteObject.description)
})()

I have also tried:

await page.click('button[data-var]="loginBtn"');
Share Improve this question edited Sep 10, 2020 at 21:46 Blue asked Sep 7, 2020 at 19:04 BlueBlue 2511 gold badge9 silver badges28 bronze badges 1
  • page.waitForSelector('[data-path="join or login"], [data-path="sign in"]') is simpler than Promise.race and ._remoteObject circumvents the public API--not a good idea. – ggorlen Commented Jun 3, 2024 at 23:17
Add a ment  | 

3 Answers 3

Reset to default 7

Try it:

await page.click('button[data-var="loginBtn"]');

They are A/B testing their website, so you may land on a page with very different selectors than you retreived while you visited the site from your own chrome browser.

In such cases you can try to grab the elements by their text content (unfortunately in this specific case that also changes over the designs) using XPath and its contains method. E.g. $x('//span[contains(text(), "Sign In")]')[0]

So I suggest to detect both button versions and get their most stable selectors, these can be based on data attributes as well:

A

$('[data-path="sign in"]')

B

$('[data-path="join or login"]')

Then with a Promise.race you can detect which button is present and then extract its selector from the JSHandle@node like this: ._remoteObject.description:

{
  type: 'object',
  subtype: 'node',
  className: 'HTMLButtonElement',
  description: 'button.nav-btn.p0-sm.body-3.u-bold.ml2-sm.mr2-sm',
  objectId: '{"injectedScriptId":3,"id":1}'
}

=>

button.nav-btn.p0-sm.prl3-sm.pt2-sm.pb2-sm.fs12-nav-sm.d-sm-b.nav-color-grey.hover-color-black

Example:

const browser = await puppeteer.launch({
  headless: false,
  defaultViewport: null,
  args: ['--start-maximized']
})
const page = await browser.newPage()
await page.goto('https://www.nike./')
const winner = await Promise.race([
  page.waitForSelector('[data-path="join or login"]'),
  page.waitForSelector('[data-path="sign in"]')
])

await page.click(winner._remoteObject.description)

FYI: Maximize the browser window as well to make sure the elment has the same selector name.

defaultViewport: null, args: ['--start-maximized']

Chromium starts in a bit smaller window with puppeteer by default.

You need to use { waitUntil: 'networkidle0' } with page.goto

This tells puppeteer to wait for the network to be idle (no requests for 500ms)

const puppeteer = require('puppeteer');

(async () => {
    const browser = await puppeteer.launch({
        headless: false,
        defaultViewport: null,
        args: ['--start-maximized']
    })

    const page = await browser.newPage()

    // load the nike. page and wait for it to fully load (inc A/B scripts)
    await page.goto('https://www.nike./', { waitUntil: 'networkidle0' })

    // select whichever element appears first
    var el = await page.waitForSelector('[data-path="join or login"], [data-path="sign in"]', { timeout: 1000 })

    // execute click
    await page.click(el._remoteObject.description)
})()
发布评论

评论列表(0)

  1. 暂无评论