如何使用 Puppeteer 获取页数?

How to get number of pages using Puppeteer?

我是使用 Puppeteer 的爬行初学者。我成功地抓取了以下网站。以下是从商城中提取特定商品名称的代码。

const express = require('express');
const puppeteer = require('puppeteer');
const app = express();

(async () => {

    const width = 1600, height = 1040;

    const option = { headless: true, slowMo: true, args: [`--window-size=${width},${height}`] };

    const browser = await puppeteer.launch(option);
    const page = await browser.newPage();
    const vp = {width: width, height: height};
    await page.setViewport(vp);

    const navigationPromise = page.waitForNavigation();

    // 네이버 스토어팜
    await page.goto('https://shopping.naver.com/home/p/index.nhn');
    await navigationPromise;
    await page.waitFor(2000);

    const textBoxId = 'co_srh_input';
    await page.type('.' + textBoxId, '양말', {delay: 100});
    await page.keyboard.press('Enter');

    await page.waitFor(5000);
    await page.waitForSelector('ul.goods_list');
    await page.addScriptTag({url: 'https://code.jquery.com/jquery-3.2.1.min.js'});

    const result = await page.evaluate(() => {

        const data = [];

        $('ul.goods_list > li._itemSection').each(function () {

            const title = $.trim($(this).find('div.info > a.tit').text());
            const price = $(this).find('div.info > .price .num').text();
            const image = $(this).find('div.img_area img').attr('src');

            data.push({ title, price, image })

        });

        return data;

    });

    console.log(result);
    await browser.close();

})();

app.listen(3000, () => console.log("Express!!!"));

我有一个问题。如果我想从页数中获取信息,我该怎么办? 例如(第 1 页、第 2 页、第 3 页 ....)

  if (!this.browser) {
    this.browser = await puppeteer.launch(this.OPT)
    const pages: puppeteer.Page[] = await this.browser.pages()

    // close chromium by catching 'targetdestryed'
    this.browser.on('targetdestroyed', async () => {
      if (this.browser) {
        const pages: puppeteer.Page[] = await this.browser.pages()
        if (pages.length === 0) {
          process.exit(0)
        }
      }
    })
  }

以上是我用Typescript写的代码。 您可以从 browser.pages() 获取页面数组(=Tab) Puppeteer 第一次绝对有 1 个选项卡。

由于默认情况下该站点上显示的页面数量的性质,这是一个困难的过程。但请耐心等待:我将向您展示您至少可以通过这个实现什么。

首先,您提供的网站在您可以循环浏览的项目列表下方一次列出 10 个页面。很抱歉,我不懂它使用的语言,所以我不知道是否有某个地方可以显示更多页面。因此,当您输入搜索文本时,它会显示如下:

但是,当您单击最后一个数字(数字 10)时,页面列表更新如下:

这使得查找总页数变得更加困难,因为没有 "jump" 到最后一页的选项(随后也没有跳回到第一页的选项)。稍后我将向您展示另一个执行此操作的网站示例。

针对您的情况,我建议您使用一些简单的数学方法来确定要列出的确切页数。将 puppeteer 告诉 "keep clicking the last available page number until you reach the end" 或类似的东西会变得太复杂了。但是我们可以通过执行几个简单的步骤来确定有多少页。

首先,您需要通过此元素获取搜索列表中返回的项目总数:

您可以通过执行以下代码来做到这一点:

const totalItems = await page.$eval('._productSet_total', (items) => {
  // Remove the characters before the total number, leaving only the number in isolation
  const child = items.querySelector('em');
  items.removeChild(child);

  // Now remove all commas from the total number
  let finalItems = items.textContent.trim();
  while(finalItems.indexOf(',') > -1) {
    finalItems = finalItems.replace(',', '').trim();
  }
  return finalItems;
});
console.log(totalItems); // Outputs 4337903 (or something similar)

所以现在你有了那个总数。下一步是确定每个页面上要显示多少项目。您可以通过计算当前页面上显示的项目数来做到这一点 - 如下所示:

const itemsPerPage = await page.$$eval('.goods_list li', (items) => {
  return items.length;
});
console.log(itemsPerPage); // Outputs 180 on my machine

现在您已找到找到的项目总数以及要在每个页面上显示的项目数。下一部分是简单的数学运算,以确定列出所有这些项目需要多少页:

const pages = totalItems / itemsPerPage;
console.log(Math.ceil(pages));

就是这样!由于网站本身的设计不佳,这是一个相当困难的示例(实际上它应该始终有一条直接到达第一页和/或最后一页的路线)。

例如,如果您在 Stack Overflow(这个非常棒的网站)中单击 puppeteer 标签,它将带您到:https://whosebug.com/questions/tagged/puppeteer

现在滚动到页面底部,您会看到如下内容:

这是确定在一个简单的步骤中列出了多少页的理想选择,如下所示:

const lastPage = await page.$$eval('div[class*="pager"] > a > span[class*="page-numbers"]', (spans) => {
  return spans[spans.length - 2].textContent;
});
console.log(lastPage); // Outputs 78

希望这里的内容对您的人偶学习之旅有所帮助!

将属性 footerTemplatedisplayHeaderFooter 一起用于最初使用 puppeteer 的显示页面 API

await page.pdf({
  path: 'hacks.pdf',
  format: 'A4',
  displayHeaderFooter: true,
  footerTemplate: '<div><div class='pageNumber'></div> <div>/</div><div class='totalPages'></div></div>'
});

https://github.com/puppeteer/puppeteer/blob/master/docs/api.md#pagepdfoptions

// footerTemplate HTML 打印页脚模板。

// 应该是有效的 HTML 标记,带有以下 CSS 类 用于将打印值注入其中:

// - 日期 格式化打印日期

// - 标题文档标题

// - url 文档位置

// - pageNumber 当前页码

// - 总页数 文档总页数