外链美化实践:自动生成网站预览卡片
群友问:输入一个网址,获取网站标题、描述和卡片的功能怎么做?
正好最近我也在考虑给落地页添加一个「Showcases」模块,用于展示使用了我的落地页模板的网站。问题对口,开始思考!
学过《爬虫从入门到入狱精通》的开发者都知道,网站的所有基本信息可以在 metadata 信息里提取。这样目标就很明确了,只要写出一个工具类,实现抓取 metadata 信息,再分析提炼,返回页面所需的信息就可以自定义渲染样式了。
本文基于 Next.js app router 实现,读完本文你能学到:
- 预览卡片需要展示哪些信息
- 模拟浏览器请求读取 dom
- 分析 metadata 并读取关键信息
知识点很少,实现单一功能的工具类就是这么简单。
预览卡片需要展示哪些信息
metadata 对于网站和搜索引擎(或者说爬虫)来说是双向奔赴的元素,更完善的 metadata 可以让搜索引擎获取更多有价值的信息,反过来,有价值的信息越多,搜索引擎就越可能把网站标记为高价值的网站,让更多人搜索到,提升网站流量。
也就是说,如果一个网站希望被更多人看到、如果你想获取这个网站的信息,你只要去看 metadata 就够了。
对于用于生成预览卡片,metadata 可能提供的信息会有这么多:
- 标题(Title):网页的主标题
- 描述(Description):简短的网页内容概述
- 图片(OG Image):metadata 里的 open graph image 或者 twitter card image
- URL:网站地址
- favicon:网站的logo
- 发布日期:对于新闻或博客文章特别有用
- 作者信息:对于个人博客或新闻网站很有帮助
- 阅读时间估计(对于文章类网页):给读者一个大致的时间预期
- 主题或分类:帮助用户快速了解内容类型
- 社交媒体互动数据:如点赞数、分享数等
- 简短的内容预览:比描述更详细一些的内容摘要
但绝大部分预览卡片不会这么复杂,我们抓取这几个信息就够了:
本文的分享也围绕获取这几个关键信息来实现工具类。
实现工具类
重申一遍这个工具类解决的需求:传入网址 URL,返回预览卡片所需的信息。
实现这个工具类有几个步骤:
- 判断传入的 URL 是否符合规则
- 模拟浏览器请求,抓取 DOM
- 分别从 DOM 信息分析并读取 title、description、favicon 和 OG image
- 返回抓取到的关键信息
先写一个方法的入口:
判断传入的 URL 是否符合规则
写一个方法,判断传入的 URL 是否符合规则:
在 scrape
里调用 normalizeUrl
:
模拟浏览器请求,抓取 DOM
模拟浏览器请求可以直接用 fetch;抓取 DOM 建议使用 jsdom 依赖包,它可以在 Node 环境模拟浏览器访问网站,然后解析 HTML 并创建虚拟 DOM 树。
在请求代码里,有两个要点:
- 我们添加了 User-Agent 头,按照最佳实践留下了联系信息,这样如果网站方不愿意被抓取信息可以联系到我们。
- 我们设置了redirect: 'follow',这表示抓取代码会自动跟随网站重定向
如果要确认获取的 document 对象是否和页面对应,可以通过 console.log(console.log(document.documentElement.outerHTML))
打印出来的信息做对比。
分析并读取 title、description、favicon 和 OG image
在任意网站里,title、description、favicon 和 OG image 都可能存在于 head 里的多个位置。
以 title 为例,除了可能在 <title>
标签里,还可能在 meta 的 og 信息里,或者 twitter card 信息里,甚至可能就是一个 h1 标签。基于这样的分析,我们可以实现一个抓取 title 的方法:
类似的,可以得到 抓取 description、favicon 和 OG image 的方法:
这样就能返回预览信息了:
一个完整的 scrape
方法就完成了。
页面使用
因为我们是在 Next.js 项目里开发,而且上面的工具类需要运行在 Node 环境,所以我们可以在 Next.js 的服务端组件里调用:
这里拿到 previewInfo 就可以在页面上渲染了。
升级版本
验证成功后,我觉得这样还不够方便,因为我需要展示很多使用案例,我想增加两点需求:
- 传入多个网址,可以返回预览信息的数组
- 支持自定义 metadata 信息,即如果传入的信息里存在自定义的 metadata 信息,则程序不去抓取,而是使用自定义值
实现起来也很简单,第一个需求,只要使用 promise.all
去批量处理 map
出来的 promise 方法,再修改一下返回结构就可以;第二个需求只要在抓取信息前判断是否已有自定义值就可以。
是闲出来的完整代码如下:
页面调用方法:
实际效果可以到 Landing Page Boilerplate 查看。
结语
本文的实现效果主要是用于解决自己项目的需求,如果你对展示网站预览卡片需求、场景研究比较深入,可以基于本文实现的工具类二次开发一个普适版本发布 npm 包,相信会有不少下载。
关于我
我是一名全栈工程师,Next.js 开源手艺人,AI降临派。
今年致力于 Next.js 和 Node.js 领域的开源项目开发和知识分享。
欢迎在以下平台关注我: