【问题标题】:How to scrape image src the right way using puppeteer?如何使用 puppeteer 以正确的方式抓取图像 src?
【发布时间】:2022-12-03 10:59:18
【问题描述】:

我正在尝试创建一个可以从网站捕获 src 属性的函数。但是所有最常见的方法都不起作用。

这是我最初的尝试。

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();

  try {
    await page.setDefaultNavigationTimeout(0);
    await page.waitForTimeout(500);

    await page.goto(
      `https://www.sirved.com/restaurant/essex-ontario-canada/dairy-freez/1/menus/3413654`,
      {
        waitUntil: "domcontentloaded",
      }
    );

    const fetchImgSrc = await page.evaluate(() => {
      const img = document.querySelectorAll(
        "#menus > div.tab-content >div > div > div.swiper-wrapper > div.swiper-slide > img"
      );
      let src = [];
      for (let i = 0; i < img.length; i++) {
        src.push(img[i].getAttribute("src"));
      }
      return src;
    });

    console.log(fetchImgSrc);
 } catch (err) {
    console.log(err);
  }

  await browser.close();
})();

[];

在我的下一次尝试中,我尝试了一个建议并返回了一个空字符串。

    await page.setViewport({ width: 1024, height: 768 });
    
    const imgs = await page.$$eval("#menus img", (images) =>
      images.map((i) => i.src)
    );

    console.log(imgs);

在我最后的尝试中,我接受了另一个建议,并返回了一个包含两个空字符串的数组。

    const fetchImgSrc = await page.evaluate(() => {
      const img = document.querySelectorAll(".swiper-lazy-loaded");
      let src = [];
      for (let i = 0; i < img.length; i++) {
        src.push(img[i].getAttribute("src"));
      }
      return src;
    });

    console.log(fetchImgSrc);

在每次尝试中,我只替换了代码的函数和控制台日志部分。我做了很多挖掘,发现这些是使用 puppeteer 删除图像 src 的最常见方法,我已经以其他方式使用它们,但出于某种原因,它们现在对我不起作用。我不确定我的代码中是否有错误或为什么它不起作用。

【问题讨论】:

  • 你能分享页面的网址吗
  • 它确实返回了第一个元素的来源,你能告诉我们你到底想做什么吗,这样我们就可以相应地编码
  • 我正在尝试返回此页面上两个菜单图像的 src 链接。但是在我的代码中我没有得到任何回报
  • 嗨@EverettDeLeon,你能试试我的答案吗,让我知道它是否适合你4

标签: node.js image web-scraping puppeteer


【解决方案1】:

要返回此页面上两个菜单图像的 src 链接,您可以使用

const fetchImgSrc = await page.evaluate(() => {
    const img = document.querySelectorAll('.swiper-lazy-loaded');
    let src = [];
    for (let i = 0; i < img.length; i++) {
       src.push(img[i].getAttribute("src"));
    }
    return src;
});

这给了我们预期的输出

['https://images.sirved.com/ChIJq6qqqlrZOogRs_xGxBcn0_w/5caf3b9eabc40.jpg', 'https://images.sirved.com/ChIJq6qqqlrZOogRs_xGxBcn0_w/5caf3bbe93cc6.jpg']

【讨论】:

  • 我试过了但没有运气
  • 当你尝试这个时你得到了什么输出?
  • [" "] 这就是回报。
【解决方案2】:

你在这里有两个问题:

  1. 默认情况下,Puppeteer 在较小的窗口中打开页面,要抓取的图像是 lazy loaded,而它们不在视口中:它们不会被加载(甚至没有 src-s)。您需要使用 page.setViewport 将您的 puppeteer 浏览器设置为更大的尺寸。
  2. Element.getAttribute 如果您正在使用动态更改的网站,则不建议这样做:它将始终返回原始属性值,即延迟加载图像中的空字符串。您需要的是在 DOM 中始终保持最新的 src 属性。这是JavaScript中attribute vs property值的话题。

    顺便说一句:您可以像这样使用page.$$eval 缩短您的脚本:

    await page.setViewport({ width: 1024, height: 768 })
    const imgs = await page.$$eval('#menus img', images => images.map(i => i.src))
    console.log(imgs)
    

    输出:

    [
      'https://images.sirved.com/ChIJq6qqqlrZOogRs_xGxBcn0_w/5caf3b9eabc40.jpg',
      'https://images.sirved.com/ChIJq6qqqlrZOogRs_xGxBcn0_w/5caf3bbe93cc6.jpg'
    ]
    

【讨论】:

  • 这是一次独特的尝试,但它仍然对我不起作用。
  • 我现在看到,您处于无头模式,延迟加载确实需要进一步触发(例如向下滚动到容器)。我待会儿再看看。你的代码没有错误,它会做你想做的事(如果你添加更大的视口)。
  • 如果我用头运行浏览器,你说你当前的功能有效吗?我不介意这样做。
  • 它实际上更早地抓取了两张图片。从今天开始,它只返回第一张图片的 src。所以我认为我的解决方案目前还没有为您提供最稳定的解决方案。我会尝试微调它:)
【解决方案3】:

看起来问题可能是当您尝试获取图像的 src 属性时图像尚未加载。在您的代码中,您正在调用 page.setDefaultNavigationTimeout(0) 禁用默认导航超时,这意味着 page.goto 函数不会等待页面完成加载后再继续。这意味着当您尝试获取图像的 src 属性时,它们可能尚未加载,因此没有要检索的 src 属性。

要解决此问题,您可以尝试使用 waitForSelector 函数等待图像加载完毕,然后再尝试获取它们的 src 属性。这是您如何执行此操作的示例:

await page.waitForSelector("#menus img");

const imgs = await page.$$eval("#menus img", (images) =>
  images.map((i) => i.src)
);

console.log(imgs);

如果您想在继续之前等待特定条件(例如具有 src 属性的图像),您也可以尝试使用 waitFor 函数而不是 waitForSelector

【讨论】:

    猜你喜欢
    • 2020-06-08
    • 2023-03-16
    • 1970-01-01
    • 2012-08-28
    • 2016-11-30
    • 1970-01-01
    • 1970-01-01
    • 2010-11-12
    • 1970-01-01
    相关资源
    最近更新 更多