【问题标题】:No node for selector while using puppeteer on facebook messenger在 facebook messenger 上使用 puppeteer 时没有选择器节点
【发布时间】:2020-06-07 18:11:14
【问题描述】:

我正在使用 Puppeteer 为我的家庭项目制作一个 Facebook Messenger api(某种)。

到目前为止,我可以使用 puppeteer 成功登录我的帐户。

当我想在登录后自动化时,真正的问题就开始了。

我无法点击任何元素。


例如

我想点击小“i”图标

然后我复制了像这样的选择器:

我在 console 中收到以下错误:

(node:4771) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 1): AssertionError [ERR_ASSERTION]: No node found for selector: #cch_feb64f1b00e628 > div._5742 > ul > li:nth-child(4) > a > div > svg
(node:4771) [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.

代码

const puppeteer = require('puppeteer');

(async function() {

    // This function is used to login into the account.
    async function login() {
        console.log('=====In Login=====');
        const email = '#email';
        const pass = '#pass';
        const submit = '#loginbutton';
        await page.waitFor(3000);
        await page.click(email);
        await page.waitFor(2000);
        await page.keyboard.type('not_a_real_email@mail.com');
        await page.waitFor(2000);
        await page.click(pass);
        await page.waitFor(2000);
        await page.keyboard.type('not_a_real_password');
        await page.waitFor(2000);
        await page.click(submit);
        return 0;
    }

    const browser = await puppeteer.launch({ headless: false });
    const page = await browser.newPage();


    page.on('load', () => console.log('=====Page loaded!====='));

    await page.goto('https://messenger.com');
    await login();
    await page.waitForNavigation();
    await page.waitFor(3000); // I'm waiting just for safe side to make sure the element is loaded.

    // This is the line where the 'i' is clicked.
    // This is the line error occurs.
    await page.click(
        '#cch_feb64f1b00e628 > div._5742 > ul > li:nth-child(4) > a > div > svg'
    );

})();

所以,根据上面的错误,我知道选择器是错误的。那么正确的选择器是什么?不仅如此,当我在表情符号元素等其他元素上尝试它时,我也遇到了同样的错误。

【问题讨论】:

  • “cch_feb64f1b00e628”或“div._5742”是否可能是动态生成的并且每次运行都不同?编辑:看起来您正在尝试单击 svg 元素而不是父锚标记。你可以试试这个选择器吗?
  • @cadmium 我很快查了一下。 #cch_feb64f1b00e628 是为每次登录动态生成的。那么,有没有其他方法可以选择呢?
  • 我有点生疏了,但你可以用 '[data-testid="info_panel_button"]' 来选择它。那应该返回锚按钮。
  • @cadmium 3 个元素(语音通话、视频通话、“i”)被包裹在 <ul> 标签内,并且其选择器是动态生成的。那么,除了那个选择器之外,还有什么方法可以获取元素呢?就像使用正则表达式来获取该元素一样。
  • @cadmium 如何通过 puppeteer 访问[data-testid="info_panel_button"]

标签: javascript node.js facebook automation puppeteer


【解决方案1】:

问题似乎是您使用的选择器是在运行时动态生成的,并且每次页面刷新都会更改。假设您只想单击 I(信息)按钮,以下使用 data-testid 的单击/选择器对我有用:

await page.click(
    '[data-testid="info_panel_button"]'
);

如果您想测试顶部的其他图标,很遗憾,它们似乎没有相同的 data-testid,这意味着选择它们会更具挑战性。

完整示例

const puppeteer = require('puppeteer');

(async function() {

  // This function is used to login into the account.
  async function login() {
    console.log('=====In Login=====');
    const email = '#email';
    const pass = '#pass';
    const submit = '#loginbutton';
    await page.waitFor(3000);
    await page.click(email);
    await page.waitFor(2000);
    await page.keyboard.type('not_a_real_email@mail.com');
    await page.waitFor(2000);
    await page.click(pass);
    await page.waitFor(2000);
    await page.keyboard.type('not_a_real_password');
    await page.waitFor(2000);
    await page.click(submit);
    return 0;
  }

  const browser = await puppeteer.launch({ headless: false });
  const page = await browser.newPage();


  page.on('load', () => console.log('=====Page loaded!====='));

  await page.goto('https://messenger.com');
  await login();
  await page.waitForNavigation();
  await page.waitFor(3000); // I'm waiting just for safe side to make sure the element is loaded.

  // This is the line where the 'i' is clicked.
  // This is the line error occurs.
  await page.click(
      '[data-testid="info_panel_button"]'
  );})();

【讨论】:

  • 但是我们不能使用title属性来选择标签吗?正如您所提到的,上述内容对“i”非常有用,但其他标签呢?我们可以根据title 等其他属性选择标签吗?我尝试了title,但失败并出现错误。还有其他方法吗?还是我应该深入到page.evaluate() 迭代标签并自己找到标题属性?我认为使用document.getElementxxxx() 方法是访问所有元素的方法之一。
  • 是的,您可以使用标题(或大多数其他元素)await page.click(''[title="Start a video chat"]'') 应该可以工作。这些特定按钮的缺点是它们会产生一个新窗口。我不确定如何在 puppeteer 中处理这个问题,tbh。
  • 我想我必须尝试一下并将其作为一个新问题发布。感谢您的回答。这对我的项目真的很有帮助。
  • 我再次阅读了 puppeteer api 并找到了关于 page.$$(selector) 的信息。为了防止在新窗口中打开,我们可以使用let elements = await page.$$('[title="Conversation information"]'); 然后elements[0].click({ button: 'left' });
猜你喜欢
  • 1970-01-01
  • 2021-11-25
  • 2018-01-29
  • 1970-01-01
  • 2019-04-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多