我是使用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页....)
答案 0 :(得分:2)
由于默认情况下在该站点上显示多少个页面的性质,这是一个困难的任务。但是请忍受:我将向您展示至少可以通过此方法实现的目标。
首先,您提供的网站在您可以循环浏览的项目列表下方一次列出了10页。很抱歉,我不理解它所使用的语言,所以我不知道是否有一个选项可以显示更多页面。因此,当您输入搜索文字时,其显示如下:
但是,当您单击最后一个数字(数字10)时,页面列表将更新为:
这使得查找总页面数变得更加困难,因为没有选择“跳转”到最后一页(随后也没有选择返回到第一页)。稍后,我将向您展示执行此操作的网站的另一个示例。
在这种情况下,我建议您使用一些简单的数学方法来确定要列出的页面数。例如,要不断告诉puppeteer
“持续单击最后一个可用的页码,直到到达末尾”,将变得非常复杂。但是我们只需执行几个简单的步骤就可以确定有多少页。
首先,您需要通过此元素获取搜索列表中返回的商品总数:
您可以通过执行以下代码来做到这一点:
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
现在滚动到页面底部,您将看到类似这样的内容:
这是确定一个简单步骤中列出多少页的理想方法,如下所示:
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个标签。