nodejs实现网站截图接口

需求:通过一个网站链接获取网站的完整截图

接到需求的第一时间我就想到了puppeteer,然后直接就在我的node项目中开始开发,当下就遇到了很多问题

puppeteer安装失败

原因:puppeteer安装时会自动下载几百兆的chrome浏览器,所以很多时候会安装失败 解决办法:手动下载 Chrome 可执行文件,启动的时候指定chrome目录

step1:下载chrome

注意:mac、linux和windows分别对应不同的chrome版本,上面下载地址可以选择环境,我本机是windows,服务器是linux,所以下载了windows和linux

step2:修改chrome启动参数

本机调试的时候,把chrome解压到自己想要的目录下,然后修改启动参数,这里要注意:

  • windows和linux的chrome的可执行文件不一样,所以要记得区分一下
  • chrome路径一定不要写错,这里根据需要替换成自己存放chrome的路径
js 复制代码
// 获取chrome路径
export const getChromePath = () => {
  if (isDev()) {
    return 'D:/tools/chrome-win/chrome.exe'
  } else {
    return '/tools/chrome-linux/chrome'
  }
}

// 启动chrome,手动指定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,现在可以截图了,但是又发现一个新的问题,网页中的图片是空白的

网页中的图片截取不全

原因:目前是一打开页面就直接截图,而网页图片加载是需要时间的,更何况还有的网址使用了图片懒加载,只渲染一屏内容

解决办法:让页面滚动到地步

js 复制代码
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根据自己情况调整。

接下来就是往服务器部署了,把chrome-linux压缩包上传到服务器,解压到代码目录的上一层,然后启动服务,调用截图接口又发现问题

linux系统中启动chrome失败

报错信息: /data/apps/tools/chrome-linux/chrome: error while loading shared libraries: libatk-1.0.so.0: cannot open shared object file: No such file or directory

原因:linux环境运行chrome时需要安装一些依赖项

解决办法:

  • 进入chrome所在目录执行:ldd chrome | grep not,该命令会列出所有缺失的包
  • 然后安装所有缺失的包
    • 注意:这些包名有时候并不准确,会导致安装时找不到这些包
    • 因为不同的 Linux 发行版本可能使用不同的软件包管理工具和包名称
    • 这里我查看了下自己的发行版版本:lsb_release -a
    • 然后把发行版本信息提供给chatgpt,让gpt给我推荐了一下包名

我的服务器版本信息: 我的版本信息如下: LSB Version: :core-4.1-amd64:core-4.1-noarch Distributor ID: AlibabaCloud Description: Alibaba Cloud Linux release 3 (Soaring Falcon) Release: 3 Codename: SoaringFalcon

下载依赖包命令:

js 复制代码
sudo yum install atk at-spi2-atk libdrm libX11 libXcomposite libXdamage libXext libXfixes libXrandr libgbm pango cairo alsa-lib

ok,现在依赖项都安装好了,再次调用screenshot接口,又发现一个问题

禁用沙箱模式

原因:Chrome 默认情况下会尝试以沙箱模式运行,但在 root 用户下运行时,这可能会受到限制

解决办法:禁用沙箱模式

js 复制代码
// 启动chrome时添加一个参数,禁用沙箱模式
const browser = await puppeteer.launch({
    executablePath: chromeFullPath,
    args: ['--no-sandbox']
});

ok,改了代码重新发包部署后,接口终于通了,且能完美的截图了

注意:截的图片不要保存在项目目录中,否则使用pm2监听服务的话,会导致服务重启

这个问题是因为我测试功能时,把截的图片放到项目目录导致的,正常不会存到项目目录下

相关推荐
GISer_Jing5 分钟前
前端面试通关:Cesium+Three+React优化+TypeScript实战+ECharts性能方案
前端·react.js·面试
落霞的思绪1 小时前
CSS复习
前端·css
咖啡の猫3 小时前
Shell脚本-for循环应用案例
前端·chrome
百万蹄蹄向前冲5 小时前
Trae分析Phaser.js游戏《洋葱头捡星星》
前端·游戏开发·trae
朝阳5816 小时前
在浏览器端使用 xml2js 遇到的报错及解决方法
前端
GIS之路6 小时前
GeoTools 读取影像元数据
前端
ssshooter7 小时前
VSCode 自带的 TS 版本可能跟项目TS 版本不一样
前端·面试·typescript
你的人类朋友7 小时前
【Node.js】什么是Node.js
javascript·后端·node.js
Jerry7 小时前
Jetpack Compose 中的状态
前端
dae bal8 小时前
关于RSA和AES加密
前端·vue.js