【问题标题】:unable to get a specific list of elements using puppeteer无法使用 puppeteer 获取特定的元素列表
【发布时间】:2021-08-24 22:20:06
【问题描述】:

我以前从未使用过这个库,所以如果这听起来像是一个愚蠢的问题,我深表歉意

所以,我想从这个网站中提取一些特定的文本

https://www.unieuro.it/online/

我已经拥有 browser.js,以及使 puppeteer 工作的所有要求

所以我只是导航到那个网站并让它搜索一些东西

请记住,这只是一个代码示例

await page.goto("https://www.unieuro.it");
await page.waitForSelector('input[name=algolia-search]');
await page.type("input[name=algolia-search]","echo dot")
await page.click(".icon-search")

到目前为止,没有什么奇怪的,它按预期工作,但是在这一步之后,事情很快就变得奇怪了。

首先,我完全无法让它等待任何选择器。 我试图让它等待类collapsed hits__hit,对于元素文章,甚至部分,它每次都会超时,所以我放弃并使用了

await page.waitForTimeout(3000);

从这里我试图提取具有类的元素:product-tile

具体来说,我需要标题,它位于 a 元素内,为 textContent

a 元素在 div 内,类 product-tile__title 所以我尝试的是一个简单的评估

var name = await page.$$eval(".product-tile__title" el => {
    el.map(el => el.querySelector("a").textContent))
    return el
})

这根本不起作用,它在一个数组中给了我一堆空对象

所以我尝试安装一个名为 puppeteer recorder 的扩展程序,并尝试使用它生成的代码

 const element1 = await page.$('.collapsed:nth-child(1) > .product-tile > .item-container > .info > .title')

在这种情况下,element1 确实包含某些内容,但与标题无关

现在我被卡住了,无论如何我都无法获得我需要的对象,并且互联网上的结果没有帮助。

附注:

我希望有一种更简单的方法可以在节点中制作刮刀,为什么所有库都必须如此复杂,并且永远不会像你想要的那样工作

【问题讨论】:

    标签: javascript node.js puppeteer


    【解决方案1】:

    这个页面对我来说加载时间超长,可能是因为我在地球的另一端,来自意大利,而且有一些奇怪的行为。当我通过输入 Puppeteer 来运行搜索时,页面返回 17000 个似乎完全未经过滤的结果。我没有费心去弄清楚为什么,因为我可以使用https://www.unieuro.it/online/?q=echo%20dot直接进入搜索结果页面:

    const puppeteer = require("puppeteer");
    
    let browser;
    (async () => {
      browser = await puppeteer.launch({headless: true});
      const [page] = await browser.pages();
      await page.setDefaultTimeout(10 ** 5);
      await page.setRequestInterception(true);
      page.on("request", req => {
        req.resourceType() === "image" ? req.abort() : req.continue();
      });
      await page.goto("https://www.unieuro.it/online/?q=echo%20dot");
      await page.waitForSelector(".product-tile__title");
      const titles = await page.$$eval(
        ".product-tile__title ",
        els => els.map(e => e.textContent)
      );
      console.log(titles.map(e => e.trim()));
    })()
      .catch(err => console.error(err))
      .finally(() => browser?.close())
    ;
    

    输出:

    [
      'Amazon Echo Dot',
      'Amazon Echo Dot (4th gen)',
      'Amazon Echo Dot (4th Gen)',
      'Amazon Echo Dot (4th gen)',
      'Amazon Echo Dot (4th gen)',
      'Amazon Echo Dot (4th gen)'
    ]
    

    我没有对此进行过广泛的测试(例如,在有大量结果的页面上),应该有很多机会通过分析和阻止不相关的请求来缩短加载时间。

    可能更好的方法是只使用 hit the API directly 并完全跳过 Puppeteer:

    const url = "https://mnbcenyfii-dsn.algolia.net/1/indexes/*/queries?x-algolia-agent=Algolia for JavaScript (3.35.1); Browser; JS Helper (2.28.0)&x-algolia-application-id=MNBCENYFII&x-algolia-api-key=977ed8d06b718d4929ca789c78c4107a";
    const body = `{"requests":[{"indexName":"sgmproducts_prod","params":"query=echo%20dot&hitsPerPage=20&maxValuesPerFacet=20&page=0"}]}`;
    fetch(url, {method: "post", body})
      .then(response => {
        if (!response.ok) {
          throw Error(response.status);
        }
        
        return response.json();
      })
      .then(data => data.results[0].hits.map(e => e.title_it))
      .then(results => console.log(results))
      .catch(err => console.error(err))
    ;

    您可以使用node-fetchaxios 轻松将其移植到Node。

    【讨论】:

    • 哇,谢谢,我什至不知道他们有 api,不,不是你,页面太糟糕了,这就是为什么我有点假设他们关闭了他们的 api,反正我已经最后设法自己找到了解决方案,我仍然会将其标记为解决方案,因为它与我所做的相同
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-10-23
    • 2019-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    相关资源
    最近更新 更多