我还是踩上了网页截图的坑

最近做了个实现网页缩略图的项目,其中不免需要用到网页截屏。

一开始想的是看看能不能在前端直接实现截图,因为Web端的截图并生成图片并不算是一个高频的需求,网上资料自然也不算多,查来查去,发现JavaScript 目前还不能实现真正意义上的网页截屏,未来如果能够实现,也一定是浏览器提供了相关接口,JS 去调用这些接口。

既然js不能实现真正意义上的截屏,那我们能做的只有通过拿到DOM的一些信息利用canvas来生成图片。

如何将dom转换成canvas图片?自然是要一点点画到canvas里,想想都是件麻烦事。网上找来找去看看有没有现成的轮子,找到了html2canvas,通过分析 niklasvh/html2canvas,梳理了其大致的思路:

  • 遍历页面中的所有元素,提取DOM节点,填充到一个rederList,并附加是否为顶层元素/包含内容的容器等信息

  • 通过提取的css属性和元素的层级信息将rederList排序,计算出一个canvas的renderQueue

  • 遍历renderQueue,将css样式转为setFillStyle可识别的参数,依据nodeType调用相对应canvas方法,将节点对应到 canvas 上。

这个方案听起来就很复杂了,无论是排序优先级的计算还是从css到canvas的转换,毫无疑问都是些巨麻烦的事,尤其是放在真实的业务场景里,DOM模版中往往会包含复杂的样式与排版,html2canvas 足足用了20多个js来实现这层转换,复杂成度可见一斑。不过这个库封装的不错,使用起来比较简单:

html2canvas(document.body).then(function(canvas) {
   canvas.id = 'screenshotCanvas'
   document.body.appendChild(canvas)
});

此时,页面的截图已经 append 到了 body 中了。虽然过程是很复杂,但是已经有了这些轮子,我们了解原理就好,人家有现成的库可以用,那咱们就不要再花费力气去造轮子,不好玩。

说了这么多这个canvas的方案,但是我最终还是没有选择它,因为我的网页里面有不少图片,都是外域资源,而这套方案我认为最大的问题就是:无法跨域加载资源 (虽然html2canvars补充了方案来弥补这个问题,但是对于我的项目实现起来成本都太高)

忘了说,在研究html2canvars的过程中我还发现了一个库叫rasterizeHTML.js。知乎的意见反馈功能里面的截图就是使用的这个库,原理有点类似,不过使用的是svg,所以我还是没有选择它,它也没法绕过跨域请求资源这个问题。

最后只能从node端使用 phantomJS 来实现了。phantomJS 它提供了一个截屏函数,通过它可以整屏获取页面截图,而且他支持的格式也比较多:JPG/PNG/GIF/PDF。通过简单的两句命令就可以把一个网页截取下来:

// render.js
var webPage = require('webpage')
var page = webPage.create()
page.viewportSize = { width: 1920, height: 1080 }
page.open("http://www.iqiyi.com", function start(status) {
  page.render('iqiyi_home.jpeg', {format: 'jpeg', quality: '100'})
  phantom.exit()
})

安装 phantomjs 之后执行下上面的文件:

phantomjs render.js

调用完你会发现,图片已经保存到了同目录下。

选择好方案后还是踩了不少坑,第一个就是我得想办法让它和node通信,不然我没法通过前端只传一个需要被截图的链接给node就能实现截图。

于是接着在网上找,发现又是这么复杂,动不动就是websocket的方式等,只能接着找轮子,还好有诸多前辈已经实现好了,万花丛中选择了一个比较适合我项目的叫做phantom的库解决了这问题。

走到这一步以为万事具备了,然后开干,发现截了张白屏给我,一开始以为是要截的网页数据没有加载完,于是delay了一会再去截图,发现还是白屏,这就很绝望了。

走到这一步再放弃就不好玩了,最终经过长久的debug发现,原来phantomJS没有支持到promise,而我网页请求数据走的是fetch api,phantomJS模拟浏览器打开我的网页,数据一直请求不到,打开的网页是个空的,截图自然就变成白屏了。

最后的结局是好的,就是再对promise 做了一下polyfill,实现了我想要的截图。过程也是好的,作为前端菜鸟,能学到的简直不能再多了。(最近看了看刚出来的Headless chrome,或许以后的截图我就用不到phantom了)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容