写在前面
在当今互联网时代,自动化测试、数据爬取等需求日益增多。Puppeteer,一款由Google开源的Node.js库,为开发者提供了一套强大的工具,让我们可以轻松地控制浏览器进行自动化操作。本文将带您了解Puppeteer的强大功能及其在实际应用中的运用。
一、Puppeteer简介
Puppeteer是一个Node.js库,它提供了一个高级API来通过DevTools协议控制Chrome或Chromium。简单来说,Puppeteer可以让开发者使用JavaScript代码来控制浏览器,实现自动化操作。
二、Puppeteer的核心功能
1. 自动化测试
Puppeteer可以模拟用户在浏览器中的操作,如点击、输入、滚动等,非常适合用于自动化测试。通过Puppeteer,我们可以轻松地编写端到端的测试用例,确保Web应用的稳定性。
2.页面截图
Puppeteer支持对网页进行截图,可以截取整个页面或指定元素。这一功能在生成网站缩略图、制作报告等方面非常有用。
3. 生成PDF
Puppeteer可以将网页转换为PDF文件,支持自定义页面大小、方向、边距等。这一功能在打印网页内容时非常有用。
4. 数据爬取
Puppeteer可以抓取网页内容,提取所需数据。相比传统的爬虫工具,Puppeteer能够更好地处理JavaScript渲染的页面,提高数据抓取的准确性。
三、Puppeteer实战应用
以下是一个简单的Puppeteer示例,实现自动化登录并截图保存。
首先,我们需要在项目中安装Puppeteer:
1.安装Puppeteer
npm install puppeteer
2.编写自动化脚本
(1)截图功能
const puppeteer = require('puppeteer');
const inquirer = require('inquirer');
// 延迟函数
const delay = (timer) =>
new Promise((resolve) => {
setTimeout(() => {
resolve(timer);
}, timer);
});
(async () => {
// 启动浏览器
const browser = await puppeteer.launch({
headless: true, // 开启无头模式
timeout: 0, // 默认超时为30秒,设置为0则表示不设置超时
});
const page = await browser.newPage();
// 开启拦截,方便对指定的接口请求做处理
await page.setRequestInterception(true);
page.on('request', (request) => {
// 检查请求的URL是否为HTTP,如果是,则继续请求
if (request.url().startsWith('http://')) {
request.continue();
} else {
// 如果不是HTTP(例如HTTPS),则中断请求
request.abort();
}
});
// 当然要根据业务需要跳到指定的网站去
await page.goto(`http://${envHref}erp.${domainName}`);
await delay(3000);
// 登录 输入账号密码
await page.type('input[type="text"]', this.account[env].userName);
await page.type('input[type="password"]', this.account[env].password);
// 环境区分,如果是正式环境需要输入图形验证码。测试环境则不用,直接登录
if (env === 'online') {
// 图形验证码
const verificationCode = await page.waitForSelector('#verify_image');
// 获取用户的主目录
const homeDirectory = process.env.HOME;
// 构建桌面路径
const desktopPath = path.join(homeDirectory, 'Desktop', 'verificationCode.png');
// 验证码截图,放到桌面
await verificationCode.screenshot({ path: desktopPath });
// 终端询问二维码
const userAnswer = await inquirer.prompt({
name: 'verificationCode',
type: 'input',
message: '请输入图形验证码',
});
// 输入二维码
await page.type('input[id="verifyCode"]', userAnswer.verificationCode);
}
// 点击登录
await page.click('#btnLogin');
})();
以下是 page对象上模拟用户的常用方法
page.setRequestInterception(true):是否开启请求拦截。page.on(pageFunction):拦截某个请求。page.goto(url, options): 导航到指定的URL。page.click(selector, options): 点击指定的元素。page.type(selector, text, options): 在指定的元素中输入文本。page.waitForSelector(selector, options): 等待指定的元素出现在页面中。page.waitForFunction(pageFunction, options, ...args): 等待在页面上下文中执行的函数返回值为true。page.screenshot([options]): 截取当前页面的屏幕截图。page.pdf([options]): 将页面保存为PDF。page.close(): 关闭当前页面。page.evaluate(pageFunction, ...args): 在页面上下文中执行函数。page.$(selector): 返回第一个匹配指定选择器的元素。page.$$eval(selector, pageFunction, ...args): 对所有匹配的元素执行函数。page.setViewport(viewport): 设置页面视口大小。
(2)生成PDF
const puppeteer = require('puppeteer');
(async () => {
// 启动浏览器
const browser = await puppeteer.launch();
// 打开新页面
const page = await browser.newPage();
// 跳转到指定的网页
await page.goto('https://example.com', { waitUntil: 'networkidle2' });
// 设置 PDF 生成选项
const pdfOptions = {
path: 'example.pdf', // 保存 PDF 的路径
format: 'A4', // 纸张格式
margin: {
top: '20px',
right: '20px',
bottom: '20px',
left: '20px',
},
printBackground: true, // 是否打印背景图形
};
// 将页面保存为 PDF
await page.pdf(pdfOptions);
// 关闭浏览器
await browser.close();
console.log('PDF generated successfully.');
})();
注意以下几点
waitUntil: 'networkidle2'确保在生成 PDF 之前页面上的网络活动已经空闲了一段时间,这有助于确保所有内容都已加载。printBackground: true是必要的,如果你想要 PDF 包含页面的背景颜色和图片。- 你可以根据需要调整
pdfOptions中的其他设置,例如scale,displayHeaderFooter,landscape等。
3.运行脚本
在终端中运行以下命令:
node example.js
四、关于SEO的那些事
啥是SEO
SearchEngineOptimization,即搜索引擎优化,让度娘、谷歌、必应能够更好地获取站点的内容,在搜索关键字时将站点的搜索结果排名更靠前。比如搜索淘宝,排名靠前的的自然是淘宝相关的站点。
搜索引擎会使用"蜘蛛"自动爬取站点上的静态内容,并根据据站点关键字进行分析,相关度最高的 (当然这是有搜索引擎自己的算法)就会在排名上更靠前。
业界内SEO方案通常有白帽和黑帽两种,白帽优化是指通过调整页面的内容:如head内的meta标签:
除此以外,合理地使用html语义化标签(如section、article、figure),根据段落使用正确的h1-h4标签,在img上书写alt属性,都能让搜索引擎更轻松地分析出页面的关键内容。
黑帽优化是指旁敲侧击的作弊方法,比如在我的页面内隐蔽地书写淘宝、京东等排名靠前的大型站点,从而"蹭"到大网站的访问量。
行业内是严打使用黑帽方案站点的,然而长期以来都没有良好的效果,也有部分原因是度娘故意想在这方面分一杯羹罢了。
CSR(Client Side Render)为什么不利于SEO
市面上为数众多的CSR架构构建的网站应用,也就是使用Vue、React、Angular等框架开发的单页面应用。
该类应用特点在于,html上本身没有页面的内容,框架是通过JavaScript将内容渲染到界面上,页面上原本并没有静态内容:
然而这就犯了搜索引擎优化的大忌,静态界面上没有内容,就意味着蜘蛛爬过来后,东张西望了半天,只看到了满屏的JavaScript代码。由于这只蜘蛛眼神算不上太好,它不认识JavaScript,于是乎满情怀失望地离开了。
行业内如何解决
知道了原因后,就要考虑怎么解决。如果真的有需求提过来的话。首先你不可能说我不使用框架开发,这在新时代的前端圈子里是难以置信的。
其次,SEO优化通常都可能是在后续的迭代需求中出现的,这时候你的站点可能都做得颇具规模了,想要推掉重构更不可能。所以问题就是怎么让CSR架构的站点有良好的SEO效果。
SSR
与CSR背道而驰,SSR和当年的JSP类似,是在服务端完成静态内容的为渲染,静态资源服务器直接返回渲染完成的html文件。
京东首页是典型的SSR站点,network查看其html文件即可发现,有很多内容是提前渲染好的。刷新网页时,也会发现有些内容没有"屏闪"效果,是因为它们是纯静态的内容,不依赖Ajax请求返回内容。因为SSR返回给前端的是渲染完整的html内容,搜索引擎蜘蛛跑过来自然就找到了它想要的内容。
当前主流框架均提供了SSR的解决方案,其中Vue的方案与Webpack、Vite捆绑性比较强,本质上是依靠vue-server-renderer插件,并且很难做到定制化现。React本身就是支持SSR的,但配置上非常费事,自由度比较高。除此之外,SSR由于将html渲染和JavaScript执行都放到了服务端,占用了更多的服务器资源。
Puppeteer+Nginx
假设某网站首页要做SEO,有这样一个思路——预渲染。即预先渲染好页面 的内容交给浏览器先行呈现,待JavaScript执行完成后将动态内容予以替换。
首先在html中预先编写一些内容(给蜘蛛看的)。通过Puppeteer进行自动化爬取,借助Node.js驱动Headless浏览器访问页面,待页面渲染完成后将整个页面上所有html内容都保存下来,这样就得到了渲染好的页面内容。再将这份爬取到的内容替换掉预先编写好的html中的内容,类似于动态化的骨骼屏。
这种方式的缺点在于,如果只是一个页面(首页)需要,这种方式是非常适合的,但如果是一个html里需要完成N多个页面的SEO诉求,这就是不可能完成的任务。
再假设某个网站的三级页面需要SEO,那么这个三级页就需要有一个开关,用于对它打开爬取内容的功能。打开后,Puppeteer需要启动Hleadless浏览器访问并获取到页面上全部内容。
在Nginx侧,目前效率更高的是使用OpenResty平台来创建Lua的运行环境,Lua需要做的是编写一份判断UserAgent的脚本,判断如果属于蜘蛛的话则返回对应的静态脚本,否则就正常放过。
基于以上方案,你既不需要进行SSR改造,也不需要把你的CSR站点推倒重做,就能实现完美的SEO。只不过你需要学习一些Node.js与Puppeteer的使用,还需要一位懂Lua的运维同学帮你搞定Nginx侧的流量拦截。