一、无头浏览器 Puppeteer基础介绍:
我们日常使用浏览器的步骤为:
启动浏览器、打开一个网页、进行交互。而无头浏览器指的是我们使用脚本来执行以上过程的浏览器,能模拟真实的浏览器使用场景。
有了无头浏览器,我们就能做包括但不限于以下事情:
- 对网页进行截图保存为图片或 pdf
- 抓取单页应用(SPA)执行并渲染(解决传统 HTTP 爬虫抓取单页应用难以处理异步请求的问题)
- 做表单的自动提交、UI的自动化测试、模拟键盘输入等
- 用浏览器自带的一些调试工具和性能分析工具帮助我们分析问题
- 在最新的无头浏览器环境里做测试、使用最新浏览器特性
写爬虫做你想做的事情~
二、写了一个案例demo,一起学习吧:
puppeteer无头浏览器-自动化测试、长图截取,pdf导出功能
github地址:puppeteer-demo
前面看了很多基础理论,但还是不上手,自己写个demo,瞬间清晰;
涉及到相关的知识:
1.cheerio
cheerio 是一个类似于 jQuery 的库,用于在服务器端解析和操作 HTML 文档。它提供了一种方便的方式来使用类似于 jQuery 的选择器和DOM操作,使得在服务器端对 HTML 文档进行解析和操作变得非常简单。
通过 cheerio,你可以像在客户端使用 jQuery 一样在服务器端对 HTML 文档进行操作,包括查找元素、修改内容、添加或删除元素等。这使得在服务器端进行页面分析和数据提取变得更加便捷。
在之前的代码示例中,我们使用了 cheerio 来加载从网站获取的 HTML 内容,并通过使用类似 jQuery 的语法来查找表格中的银行名称。这样可以方便地从网页中提取出需要的信息,进行进一步的处理和分析。
总的来说,cheerio 是一个非常实用的工具,特别适合在 Node.js 环境下对 HTML 文档进行解析和操作。
2. new URL(import.meta.url) 和 path.join(__dirname, …)的区别
new URL(import.meta.url):
import.meta.url 是 ES 模块中的一个特殊变量,用于获取当前模块的 URL。
通过 new URL(import.meta.url) 可以将 URL 字符串解析为 URL 对象,从而获取当前模块文件的完整路径信息。
这种方法在 ES 模块中使用较为常见。
path.join(__dirname, …):
1)__dirname 是 Node.js 中的一个特殊变量,用于获取当前模块的目录路径。
2)path.join() 方法用于拼接路径片段,并返回标准化后的路径。
这种方法在 CommonJS 模块中经常被使用。
虽然这两种方法都可以用于获取当前模块的路径信息,但在不同模块规范下(ES 模块 vs. CommonJS 模块),推荐使用相应的方式来获取路径信息以保持一致性和兼容性。
其中捕获截图,涉及到路径问题,特别研究下:
import puppeteer from "puppeteer"
import path from 'path';
async function captureScreenshot(url, outputFilePath) {
// .launch 方法启动一个浏览器实例,然后打开一个新的页面
const browser = await puppeteer.launch({ headless: true });
printColor("开始启动.......", 32);
const page = await browser.newPage();
printColor("等待页面加载完毕.......", 32);
await page.goto(url, { waitUntil: 'networkidle0' }); // 等待页面加载完成 // 确保页面加载完成后再进行下一步操作。
printColor("获取网站完整页面中.......", 32);
// 获取页面的整个高度和宽度
const bodyHeight = await page.evaluate(() => document.body.scrollHeight);
// const bodyWidth = await page.evaluate(() => document.body.scrollWidth);
// 设置视口大小和截图尺寸
await page.setViewport({ width: 1366, height: bodyHeight });
// import.meta.url 是 ES 模块中的一个特殊变量,用于获取当前模块的 URL。puppeteer-explore/puppeteer-app/short/index.mjs
const currentFilePath = new URL(import.meta.url).pathname;
// path.join() 方法用于拼接路径片段,并返回标准化后的路径。
// path.dirname(currentFilePath) 的结果是:// puppeteer-explore/puppeteer-app/short
// outputFilePath的结果是:screenshot/baidu.com.png
const outPath = path.join(path.dirname(currentFilePath), outputFilePath);
// outPath的结果就是// puppeteer-explore/puppeteer-app/short/screenshot/baidu.com.png
await page.screenshot({ path: outPath, fullPage: true });
await browser.close(); // 关闭浏览器
}
// const url = 'https://isux.tencent.com';
const url = 'https://baidu.com';
const outPath = 'screenshot/' + getMainDomain(url) + '.png'; // 不包含short目录
// const outPath = path.join(path.dirname(new URL(import.meta.url).pathname), outputFilePath);
captureScreenshot(url, outPath)
.then(() => console.log('Screenshot captured', outPath))
.catch(error => console.error(error));
function getMainDomain(url) {
const parsedUrl = new URL(url);
const hostname = parsedUrl.hostname;
// 'isux.tencent.com'
return hostname;
}
function printColor(text, color) {
const colorCode = `\u001b[${color}m`;
const textCode = `${text}\u001b[0m`;
process.stdout.write(`${colorCode}${textCode}\n`);
}