如何使用Puppeteer获取页数?

时间:2018-11-14 06:46:31

标签: javascript node.js web-crawler google-chrome-devtools 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页....)

3 个答案:

答案 0 :(得分:2)

由于默认情况下在该站点上显示多少个页面的性质,这是一个困难的任务。但是请忍受:我将向您展示至少可以通过此方法实现的目标。

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

First ten pages listed

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

More pages added dynamically

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

在这种情况下,我建议您使用一些简单的数学方法来确定要列出的页面数。例如,要不断告诉puppeteer“持续单击最后一个可用的页码,直到到达末尾”,将变得非常复杂。但是我们只需执行几个简单的步骤就可以确定有多少页。

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

Total number of results

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

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://stackoverflow.com/questions/tagged/puppeteer

现在滚动到页面底部,您将看到类似这样的内容:

enter image description here

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

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

希望这里有什么可以帮助您完成木偶学习之旅!

答案 1 :(得分:1)

使用属性 footerTemplate displayHeaderFooter 来显示最初使用操纵符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 当前页号

//-文档中的 totalPages 页总数

答案 2 :(得分:0)

  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个标签。