nodejs使用puppeteer实现网站截图接口
需求:通过一个网站链接获取网站的完整截图
接到需求的第一时间我就想到了puppeteer,然后直接就在我的node项目中开始开发,当下就遇到了很多问题
puppeteer安装失败
原因:puppeteer安装时会自动下载几百兆的Chromium,所以很多时候会安装失败 解决办法:手动下载 Chromium 可执行文件,启动的时候指定 Chromium 目录
step1:下载Chromium
注意:mac、linux和windows分别对应不同的Chromium版本,上面下载地址可以选择环境,我本机是windows,服务器是linux,所以下载了windows和linux
step2:修改Chromium启动参数
本机调试的时候,把Chromium解压到自己想要的目录下,然后修改启动参数,这里要注意:
- windows和linux的chrome的可执行文件不一样,所以要记得区分一下
- chrome路径一定不要写错,这里根据需要替换成自己存放Chromium的路径
// 获取chrome路径
export const getChromePath = () => {
if (isDev()) {
return 'D:/tools/Chromium-win/chrome.exe'
} else {
return '/tools/Chromium-linux/chrome'
}
}
// 启动Chromium,手动指定executablePath路径
const chromeFullPath = path.resolve(process.cwd(), getChromePath())
const browser = await puppeteer.launch({
executablePath: chromeFullPath
})
const page = await browser.newPage()
await page.goto(url)
const screenshotDir = path.resolve(ROOT_PATH, 'screenshot')
if (!fs.existsSync(screenshotDir)) {
fs.mkdirSync(screenshotDir)
}
const hash = crypto
.createHash('md5')
.update(`${url}_${Date.now()}`)
.digest('hex')
await page.screenshot({
fullPage: true,
path: `${screenshotDir}/${hash}.jpg`
})
await browser.close()
return {
msg: '截图成功',
pic_name: `${hash}.jpg`
}
ok,现在可以截图了,但是又发现一个新的问题,网页中的图片是空白的
网页中的图片截取不全
原因:目前是一打开页面就直接截图,而网页图片加载是需要时间的,更何况还有的网址使用了图片懒加载,只渲染一屏内容
解决办法:让页面滚动到地步
await page.goto(url)
// 滚动到页面底部,保证页面中图片都渲染出来
await page.evaluate(async () => {
await new Promise((resolve) => {
let totalHeight = 0
const distance = 300
const timer = setInterval(() => {
const scrollHeight = document.body.scrollHeight
window.scrollBy(0, distance)
totalHeight += distance
if (totalHeight >= scrollHeight) {
clearInterval(timer)
resolve('滚动完毕')
}
}, 100)
})
})
...
ok,到这里就可以截到网站中的图片了,上面的100和300根据自己情况调整。
接下来就是往服务器部署了,把Chromium-linux压缩包上传到服务器,解压到代码目录的上一层,然后启动服务,调用截图接口又发现问题
linux系统中启动Chromium失败
报错信息: /data/apps/tools/Chromium-linux/chrome: error while loading shared libraries: libatk-1.0.so.0: cannot open shared object file: No such file or directory
原因:linux环境运行Chromium时需要安装一些依赖项,不同的服务器发行版本需要安装的依赖包不一样,具体依赖包项见(不一定全):pptr.nodejs.cn/troubleshoo…
解决办法:
- 根据自己服务器的发行版本去官网查看缺少的依赖项,全局安装所有缺失的包
- 安装完如果还有确实依赖的错误,可以进入chrome所在目录执行
ldd chrome | grep not
列出所有缺失的包并进行安装即可- 注意:这些包名有时候并不准确,会导致安装时找不到这些包。比如:列出
libgbm.so.1 => not found
,实际安装时使用yum install libgbm -y
- 注意:这些包名有时候并不准确,会导致安装时找不到这些包。比如:列出
ok,现在依赖项都安装好了,再次调用screenshot接口,又发现一个问题
禁用沙箱模式
原因:Chrome 默认情况下会尝试以沙箱模式运行,但在 root 用户下运行时,这可能会受到限制
解决办法:禁用沙箱模式
// 启动chrome时添加一个参数,禁用沙箱模式
const browser = await puppeteer.launch({
executablePath: chromeFullPath,
args: ['--no-sandbox']
});
ok,改了代码重新发包部署后,接口终于通了,且能完美的截图了
注意:截的图片不要保存在项目目录中,否则使用pm2监听服务的话,会导致服务重启
这个问题是因为我测试功能时,把截的图片放到项目目录导致的,正常不会存到项目目录下
转载自:https://juejin.cn/post/7307494782279417897