html2canvas 解决某些站点截图空白问题

news/2024/12/2 14:21:32/文章来源:https://www.cnblogs.com/yz-blog/p/18581820

业务场景介绍

 

 

点击浏览器右上角已安装的chrome插件图标,这个时候会出现一个界面,我们称这个界面为popup,界面上有个"从页面获取产品信息"按钮,单机它会对当前标签页面内容进行截图,最后将截图的图片转成base64发送至xx接口

部分核心代码解读:截取当前可视区域的图片,为了能够截图足够多信息,图片向上衍生300px,向下衍生300px,那图片高度= 300 + 可视区域 + 300

const viewportWidth = window.innerWidth;
const viewportHeight = window.innerHeight;
const threshold = 300;
const scrollY = window.scrollY;
const y = scrollY > threshold ? scrollY - threshold : 0;
const h =scrollY > threshold? viewportHeight + threshold * 2: viewportHeight + threshold + scrollY;
window.html2canvas(document.querySelector('body'), {width: viewportWidth,height: h,x: window.scrollX,y: y,scrollX: 0,scrollY: 0,useCORS: true // 如果有跨域图片})

抛出问题

问题1. 经过测试,概率上百分之99%的页面都能抓取,部分页面不能抓,抓取效果如下图(页面出现了大片空白白板),如:http://www.sinochemheb.com/s/18959-55112-274763.html

 

解决思路

简单分析一波:调试模式查看页面元素没有什么特殊DOM,也没什么iframe嵌套

猜想1

可能是因为html2canvas插件问题,让gpt给出可平替方案

dom-to-image
这个库也可以将 DOM 元素渲染成图像,支持各种格式(如 PNG、JPEG 等)。它支持的特性包括:背景透明、SVG 图像支持、渐变和阴影等。

官网:https://github.com/tsayen/dom-to-image

canvas2image
canvas2image 是一个将 <canvas> 转换为图像的库。它比较轻量,简单易用,支持将 <canvas> 输出为图片(PNG、JPEG 或 BMP 格式)。

官网:https://github.com/hongru/canvas2image

rasterizeHTML.js
这个库支持将 HTML 页面渲染成图像。它能够解析 HTML 中的样式并将它们转换为一个 Canvas 图像。与 html2canvas 类似,它支持从 DOM 生成图像。

官网:https://github.com/cburgmer/rasterizeHTML.js

puppeteer
puppeteer 是一个更为强大的库,它是一个 Node.js 库,提供了一个高层次的 API 来控制 Chrome 或 Chromium 浏览器。可以用它来截图整个网页或页面的特定部分,并能处理更复杂的渲染问题,支持更复杂的 CSS 和 JavaScript 执行。

官网:https://github.com/puppeteer/puppeteer

html-to-image
这是一个简单的 JavaScript 库,用于将 HTML 元素转换为图像。它基于 canvas,并支持各种格式导出,如 PNG 和 JPEG。与 html2canvas 相比,它的 API 更简洁易用。

尝试性使用:dom-to-image

截图空白区域问题得到了解决,但抛出了更大的问题,百分之90%以上的站点都截图失败

尝试性使用:rasterizeHTML.js

很多UI样式丢失,截出来的图没发看

继续思考

最直接的方法没有效果,那就回归初始状态,研究html2canvas插件原理

为啥选择html2canvas呢?

第一:它截图出来的效果更接近与预期

第二:github的star数更最多,前人栽树后人乘凉的原理,应该没错吧

于是打开 https://github.com/niklasvh/html2canvas,翻了几页查看issues,没有找到自己想要的答案,接着看插件原理

插件底层原理

html2canvas 是一个将 HTML 页面内容转换为画布(Canvas)图像的 JavaScript 库。它通过遍历 HTML 元素,解析元素的样式、字体、颜色等信息,并通过调用 Canvas API 来绘制图像。底层原理包括以下步骤:

  1. 遍历 DOM 树html2canvas 会递归遍历 DOM 元素,分析每个元素的计算样式。
  2. 计算布局:计算元素的尺寸、位置,处理复杂的布局(如定位、浮动等)。
  3. 渲染样式:获取元素的背景色、边框、字体等信息,并转化为画布可识别的格式。
  4. 处理图像和媒体:对于图像、视频等元素,html2canvas 会加载并绘制到画布上,可能会通过跨域处理(CORS)来获取外部资源。
  5. 绘制到 Canvas:最终通过 Canvas API 渲染所有计算后的元素,生成最终图像

看到这底层原理,直呼牛逼,原来是将html转成canvas渲染,最终形成图片,那么就接着再去看下要截图的网页,分析下除了没有特殊的iframe之外还有没有特殊的内容,刷了几次页面之后,突然发现点蛛丝马迹

这网站有个从底部向上上升的一个过度效果,看了下元素

 于是大胆猜测,插件在执行截图时,将html的计算样式1:1的绘制到了canvas上,而开始时,这些带动画效果的属性是不可见的,只有在出现到可视区域才会触发显示,而canvas显然是没有这个逻辑,于是我在截图之前把这些属性都给去掉或者修改元素属性改为可见,ok,真相了,完美截图了,达到了预期效果

最终的解决方案

导致部分网站截图失败原因是因为html2canvas在往canvas绘制内容时,默认隐藏的内容也会被绘制到canvas上,导致截图出来是空白的,解决方案就是在截图之前把这些隐藏的元素给展现出来,动画的过滤效果去掉,元素显示通用代码如下

const node = document.createTreeWalker(window.document.body,NodeFilter.SHOW_ELEMENT,{acceptNode: function (node: HTMLElement) {// 如果节点是 div 元素,则接受它if (node?.tagName === 'DIV') {return NodeFilter.FILTER_ACCEPT;}return NodeFilter.FILTER_SKIP; // 如果不是 div,则跳过
    }}
);
let nextNode;
while ((nextNode = node.nextNode() as HTMLDivElement)) {const tagName = nextNode?.parentElement?.tagName;if (tagName !== 'SCRIPT' && tagName !== 'STYLE' && tagName !== 'CODE') {nextNode.style.opacity = '1';nextNode.style.visibility = 'visible';nextNode.style.animationDuration = '0s';nextNode.style.animationDelay = '0s';}
}

后续思考

除了使用document.createTreeWalker API 之外,动态往页面中插入css样式强制让div显示去除动画效果应该也是可行的

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/845421.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

领歌看板助力电商大促筹备

每年的“双11”“双12”“618”等大型电商促销活动是各企业的年度重头戏,但涉及环节众多、协作复杂,稍有疏漏就可能影响活动效果。领歌看板为您提供了一种高效、直观的任务管理方式,确保每一步都尽在掌握。 1. 全面覆盖任务场景,理清活动脉络 利用领歌看板,您可以将大促活…

.NET开发WinForm(C/S)项目整合三种SOA服务访问(直连、WCF、WebAPI)模式

在软件开发领域,尤其是企业级应用开发中,灵活性、开放性、可扩展性往往是项目成功的关键因素。对于C/S项目,如何高效地与后端数据库进行交互,以及如何提供多样化的服务访问方式,是开发者需要深入考虑的问题。目前主流的方式就三种:数据库直连、WCF模式、WebAPI模式。RDIF…

mysql 之查询条件!=或者存在问题,会被轻易忽略而且影响查询结果

mysql数据库查询,我们再使用sql条件时会经常使用!=(<>),但使用!=之后,这个字段对应的为空的值不会查出来。所以建议!=长春与is null同时用 查询结果测试如下: 我们先查询满足条件的数据;id上下相同,同时此id的对应的paln_status查询如图是空的: 咱们再来查询总…

Postman 安装与汉化超详细步骤全解析教程

下载安装包 首先,我们需要获取 Postman 的安装包。为了方便,链接提供了安装包跟汉化包 点击获取postman安装及汉化包 为什么要提供安装包跟汉化包? 汉化包和postman的版本必须是一致的,如果不一致就会出现汉化后无法打开postman的问题; 注意:如果想要汉化的就不能使用最新…

文档比对新玩法:从文本细节到逻辑洞察

在学术研究和项目管理中,文档的版本对比和差异检查往往是个被低估却至关重要的环节。尤其是在跨学科合作或大型团队中,不同版本的文档往往在细节上存在微妙变化,而这些变化可能直接影响研究结论、策略决策甚至是整个项目的方向。 传统的文档对比工具往往局限于纯文本比对,这…

有效管理win11系统开机启动项

平时如果有你不想随着系统开机就启动的软件,可以通过下面的方式进行设置。个人推荐使用这个办法 1.首先点击开始菜单2.点击“设置”3.再点击左边栏“应用”选项4.然后点击其中的“启动”设置5.选择开关按钮,即可设置启动或禁用

ai大模型流式输出------基于SSE协议的长连接实现ax

传统的http1.0请求开发,已经满足了我们日常的web开发。一般请求就像下图这样子,客服端发起一个请求(触发),服务端做出一个响应(动作): 有时会有诸如实时刷新,实时显示的场景,我们往往是客户端定时发起请求,不断的尝试获取最新的数据。但是每次请求都会创建并释放一个…

高级语言程序设计课程第十次个人作业

2024高级语言程序设计:https://edu.cnblogs.com/campus/fzu/2024C 高级语言程序设计课程第十次个人作业:https://edu.cnblogs.com/campus/fzu/2024C/homework/13314 学号:102400226 姓名:石华波 本次作业所用到的"Source.txt"文本文件均为下图文件://1202.1 #include…

也许,这就是一个新的开始吧……

准备参加招警考试了,虽然我预测当前自己的各项指标什么的基本不合格,但是我愿意尝试一把,愿上岸成功。加油吧,青中骚年。 【敬畏能量 敬畏自然】

开源工具能让项目管理更高效?2024年开源管理软件大揭秘!

一、开源项目管理的重要性在当今的项目管理领域,开源项目管理具有至关重要的意义。它鼓励创新,为开发者提供了一个开放的平台,让不同背景的人能够共同参与,分享各自的想法和经验,从而推动项目不断创新发展。 开源项目管理保证透明,项目的代码和流程对所有人可见,这使得项…

Vaccine

Vaccine 1. 扫描 上来直接扫到ftp有一个backup.zip以及ssh和80端口将backup.zip下载下来然后发现压缩包有密码2. 访问 访问80端口看看还有一些信息,apache+PHP,Linux系统首先,对于登录界面,先排除弱口令和SQL注入,然后看目录扫描结果没什么内容,那只能回头看backup.zip,…

十、Spring Boot集成Spring Security之HTTP请求授权

Spring Security最新基于HTTP请求授权配置详解:工作原理,授权配置,异常处理,测试接口,案例源码目录前言一、HTTP请求授权工作原理二、HTTP请求授权配置1、添加用户权限2、配置ExceptionTranslationFilter自定义异常处理器3、HTTP请求授权配置三、测试接口1、测试类2、测试…