无法使用 puppeteer 获取特定的元素列表

unable to get a specific list of elements using puppeteer

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

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

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

我已经 browser.js,并且满足了使人偶操作工作的所有要求

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

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

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")

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

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

await page.waitForTimeout(3000);

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

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

a 元素在 div 和 class product-tile__title 中,所以我尝试的是一个简单的 eval

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

这根本不起作用,它给了我一个数组中的一堆空 objects

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

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

在这种情况下 element1 确实包含一些内容,但它与标题没有任何关系

现在我被卡住了,我完全无法获得我需要的 object 并且互联网上的结果没有帮助。

作为旁注:

我希望有一种更简单的方法在 node 中制作爬虫,为什么所有的库都必须如此复杂并且永远不会像你希望的那样工作

这个页面对我来说有超长的加载时间,可能是因为我在地球的另一边,远离意大利,还有一些 st运行ge 行为。当我 运行 使用 Puppeteer 进行搜索时,页面 returns 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-fetch or axios 轻松地将其移植到 Node。