Использование Puppeteer для сбора ссылок на страницу и открытия этих ссылок для очистки данных

#node.js #web-scraping #puppeteer

#node.js #очистка веб-страниц #puppeteer

Вопрос:

Мне нужно очистить данные продуктов из списка, но данные находятся на страницах этих продуктов. Например, допустим, я хотел бы получить .product-image страницу продукта.

Код до сих пор успешно извлекает каждый URL и добавляет в массив, но я не уверен, куда идти дальше, так как использование по какой-то причине page возвращает Error: Evaluation failed: ReferenceError: page is not defined при использовании его вне urls .

   const page = await browser.newPage();
  page.waitForNavigation({ timeout: 0, waitUntil: "domcontentloaded" });

  await page.goto(siteSearchUrl   1);
  await page.screenshot({ path: "carpet.png" });

  const urls = await page.evaluate(() => {
    const items = document.querySelectorAll("li.product-item");
    const productLinks = [];
    console.log(page);
    items.forEach((item) => {
      const productLink = item
        .querySelector("a.product-image") // NOT the product image, it's the link.
        .getAttribute("href");
      productLinks.push(`${siteUrl   productLink}`);
    });

    productLinks.forEach((link) => {
      page.screenshot({ path: link   ".png" });
    }, page);
  });

  await browser.close();
  return Promise.resolve(urls);
})();
  

Как именно мне собирать данные по каждой из ссылок?

Ответ №1:

Невозможно использовать page внутри page.evaluate .

Вы получаете, ReferenceError: page is not defined из-за page.evaluate выполнения сценария в контексте страницы (например, вы console.log(page) вошли в консоль Chromium, а не в консоль узла), другие методы puppeteer (например, page.screenshot ) не могут быть запущены на стороне клиента, но только в puppeteer. Поэтому вам нужно переместить его наружу.

Например.:

 const urls = await page.evaluate(() => {
  const productLinks = []
  ...
  productLinks.push(...)
  ...
  return productLinks
})

for (const url of urls) {
  await page.goto(url)
  await page.screenshot({ path: url   '.png' })
}

  

Редактировать

Я исправил приведенный выше пример. Вы можете обнаружить, что можете решить проблему, используя page.$eval , page.$$eval более лаконично.

 const hrefs = await page.$$eval('li.product-item > a.product-image', elements => elements.map(el => el.href))
const urls = hrefs.map(el => siteUrl   el)

for (const url of urls) {
  await page.goto(url)
  await page.screenshot({ path: url   '.png' })
}
  

Комментарии:

1. Не будет productLinks быть udefined внутри page.evaluate() и впоследствии пустым без переноса массива между контекстами?

2. верно. действительно, я забыл, что сложно заполнить массив из контекста страницы. Я переделаю свой пример, чтобы он работал.

3. Спасибо за помощь! У меня есть один запрос — как будет выглядеть разбивка на страницы в вашем коде? Запрос для разбивки на страницы ?страница= 1.

4. вау, я думаю, что это заслуживает нового вопроса, я не уверен, что мой комментарий будет полезен для достижения того, что вам нужно. puppeteer не всегда учитывает параметры GET в URL. если вы хотите перевернуть страницу после завершения очистки текущей страницы, вы можете просто нажать на кнопку «Следующая страница», как это делает реальный пользователь: await page.click('.next-page-btn')