首页 > 解决方案 > 使用 Puppeteer 抓取多个网站

问题描述

所以我试图只从一个以上的网站(在这种情况下是 PS Store)中只抓取两个元素。另外,我正在尝试以最简单的方式实现它。由于我是 JS 的菜鸟,请保持温和 ;) 在我的脚本下方。我试图用一个 for 循环来实现它,但没有任何效果(它仍然只从数组中获得第一个网站)。非常感谢任何形式的帮助。

const puppeteer = require("puppeteer");

async function scrapeProduct(url) {
  const urls = [
    "https://store.playstation.com/pl-pl/product/EP9000-CUSA09176_00-DAYSGONECOMPLETE",
    "https://store.playstation.com/pl-pl/product/EP9000-CUSA13323_00-GHOSTSHIP0000000",
  ];
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  for (i = 0; i < urls.length; i++) {
    const url = urls[i];
    const promise = page.waitForNavigation({ waitUntil: "networkidle" });
    await page.goto(`${url}`);
    await promise;
  }

  const [el] = await page.$x(
    "/html/body/div[3]/div/div/div[2]/div/div/div[2]/h2"
  );
  const txt = await el.getProperty("textContent");
  const title = await txt.jsonValue();

  const [el2] = await page.$x(
    "/html/body/div[3]/div/div/div[2]/div/div/div[1]/div[2]/div[1]/div[1]/h3"
  );
  const txt2 = await el2.getProperty("textContent");
  const price = await txt2.jsonValue();

  console.log({ title, price });

  browser.close();
}

scrapeProduct();

标签: javascriptweb-scrapingasync-awaitpuppeteer

解决方案


一般来说,您的代码还可以。但是,应该纠正一些事情:

const puppeteer = require("puppeteer");

async function scrapeProduct(url) {
    const urls = [
        "https://store.playstation.com/pl-pl/product/EP9000-CUSA09176_00-DAYSGONECOMPLETE",
        "https://store.playstation.com/pl-pl/product/EP9000-CUSA13323_00-GHOSTSHIP0000000",
    ];
    const browser = await puppeteer.launch({
        headless: false
    });
    for (i = 0; i < urls.length; i++) {
        const page = await browser.newPage();
        const url = urls[i];
        const promise = page.waitForNavigation({
            waitUntil: "networkidle2"
        });
        await page.goto(`${url}`);
        await promise;
        const [el] = await page.$x(
            "/html/body/div[3]/div/div/div[2]/div/div/div[2]/h2"
        );
        const txt = await el.getProperty("textContent");
        const title = await txt.jsonValue();

        const [el2] = await page.$x(
            "/html/body/div[3]/div/div/div[2]/div/div/div[1]/div[2]/div[1]/div[1]/h3"
        );
        const txt2 = await el2.getProperty("textContent");
        const price = await txt2.jsonValue();

        console.log({
            title,
            price
        });

    }
    browser.close();
}

scrapeProduct();
  1. 您在循环中打开网页,这是正确的,但随后在循环之外查找元素。为什么?您应该在循环中执行此操作。
  2. 对于调试,我建议使用{ headless: false }. 这使您可以查看浏览器中实际发生的情况。
  3. 不确定您使用的是哪个版本的 puppeteer,但networkidle在最新版本中没有这样的事件npm。您应该使用networkidle0ornetworkidle2代替。
  4. 您正在通过 xpath 寻找元素html/body/div...。这可能是主观的,但我认为标准的 JS/CSS 选择器更具可读性:body > div .... 但是,好吧,如果它有效...

在我的情况下,上面的代码产生以下内容:

{ title: 'Days Gone™', price: '289,00 zl' }
{ title: 'Ghost of Tsushima', price: '289,00 zl' }

推荐阅读