单击带有操纵符的选择器

时间:2020-09-07 19:04:24

标签: javascript node.js puppeteer

所以我在单击nike网站上的登录按钮时遇到了麻烦。

我不确定为什么它一直崩溃,好吧,因为找不到我猜到的选择器,但是我不确定自己做错了什么。

我还要说的是,在puppeteer崩溃之前我遇到了某种内存泄漏,如果我不及时在控制台内取消进程的话,有时甚至会完全使我的macbook崩溃。

编辑: 每当崩溃时,此代码还会导致内存泄漏,如果我没有足够快地取消应用程序,则迫使我不得不硬重置我的mac。

节点版本:14.4.0 木偶版:5.2.1

当前代码:

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.com/')

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

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

我也尝试过:

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

3 个答案:

答案 0 :(得分:2)

它们是A/B testing的网站,因此您可能会进入一个页面,其选择器与您从自己的Chrome浏览器访问该站点时获得的选择器大不相同。

在这种情况下,您可以尝试使用XPath及其contains方法按其文本内容(不幸的是,这种情况也会更改设计)来获取元素。例如。 $x('//span[contains(text(), "Sign In")]')[0]

因此,我建议检测两个按钮的版本并获取最稳定的选择器,这些选择器也可以基于数据属性:

A

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

B

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

然后使用Promise.race,您可以检测到存在哪个按钮,然后从JSHandle@node中提取其选择器,如下所示:._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

示例:

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

await page.click(winner._remoteObject.description)

仅供参考:还要最大化浏览器窗口,以确保元素具有相同的选择器名称。

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

默认情况下,铬会在一个较小的窗口中以puppeteer开头。

答案 1 :(得分:0)

尝试一下:

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

答案 2 :(得分:0)

您需要将{ waitUntil: 'networkidle0' }page.goto一起使用

这告诉操纵up的人等待网络空闲(500毫秒内没有请求)

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.com page and wait for it to fully load (inc A/B scripts)
    await page.goto('https://www.nike.com/', { 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)
})()