背景
随着react、vue、angular等前端框架的流行越来越多的web应用变成了单页应用,它们的特点是异步拉取数据在浏览器中渲染出HTML。使用这些框架极大的提升web用户体验和开发效率的同时缺带来一个新问题,那就是这样的网页无法被搜索引擎收录。虽然这些web框架支持服务端渲染,但这可能又会增加开发成本。
如果在原有 express/koa 项目上添加一个中间件就能解决这个问题不是更好吗
HeadlessChrome介绍
前不久 Chrome 团队宣布 Chrome 支持 headless 模式,HeadlessChrome支持 Chrome 所具有的所有功能只不过因为不显示界面而更快资源占用更小。相比于之前的 phantomjs (作者因为 HeadlessChrome 的推出而宣布停止维护),Chrome 的优势在于它又一个很强的爹(Google)会一直维护它优化它,并且 Chrome 在用户量、体验、速度、稳定性都是第一的,所以我认为 HeadlessChrome 会渐渐替代之前所有的 HeadlessBrowser 方案。
如何操控HeadlessChrome
既然HeadlessChrome是以无界面模式运行的,那要怎么控制它和它交互? chrome提供了远程控制接口,目前可以通过chrome-remote-interface来用js代码向chrome发送命令进行交互。在启动chrome的时候要开启远程控制接口,然后通过 chrome-remote-interface 连接到chrome后再通过协议控制chrome。具体操作见文档:
express-middleware-seo
本项目在chrome-render 的基础上封装成一个中间件,因为作者已经基于chrome-render 出了 koa 版本的中间件而没出 express 版本的中间件的计划,所以又造了个轮子
chrome-render
原理是:
chrome-render
先会通过 chrome-runner
以 headless 模式启动和守护你操作上的 Chrome,再通过chrome-remote-interface 操控 Chrome 去访问需要被 SEO 的网页让 Chrome 运行这个网页,等到包含数据的HTML被渲染出来时读取当前网页 DOM 转换成字符串后返回。
怎么知道你的网页什么时候已经渲染出包含数据的HTML了可以返回了呢?为了提升chrome-render
效率,默认会在domContentEventFired 时返回。对于复杂的场景还可以通过开启 chrome-render
的useReady选项,等到网页里window.isPageReady
等于 1 时返回。
只渲染出了 HTML 还不够我们还需要检测出来着搜索引擎爬虫的访问,如果请求来着爬虫就返回chrome-render
渲染后的HTML否则返回正常的单页应用所需 HTML。
综上,整体架构如下:
实践
只需以下几行简单代码就可让爬虫抓到 js 执行 window.isPageReady = 1
完成后的页面
express 部分
const { seoMiddleware } = require('express-middleware-seo')
app.use(
seoMiddleware({
render: {
useReady: true
}
})
)
HTML 部分
<h1 id="app">You are not a crawler, I will be ready after 1S</h1>
<script>
setTimeout(function () {
document.getElementById('app').innerText = 'Im ready now';
window.isPageReady = 1;
}, 1000);
</script>
为什么使用 chrome-render
而不是用 prerender.io 呢, chrome-render
的优势在于
- chrome-render开源可自己部署,prerender要收费是商业产品
- prerender基于已经停止维护的phantomjs
项目地址
express 中间件:
express-middleware-seo
相关库:
chrome-render
有个疑问,使用这个中间后可以应付任意的爬虫么,比如国内比较重要的 百度爬虫。 感觉百度的seo爬虫算法有点差,基本靠和公司定制规则来收录。。。 还有这个中间件对用户使用的浏览器访问有要求么
来自酷炫的 CNodeMD
@hyj1991 只是能保证爬虫抓到的是渲染后的页面,不保证排名和权重,原理是判断 UA 是否是爬虫,如果是则提供 chrome-headless 渲染后的页面
@Binaryify 明白了,谢谢
来自酷炫的 CNodeMD
原理我看不太懂,是不是只要在node上加上中间件就ok?
@Faithree 需要安装 chrome59+,然后使用这个中间件