New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用HeadlessChrome做单页应用SEO #8

Open
gwuhaolin opened this Issue Jun 27, 2017 · 15 comments

Comments

Projects
None yet
10 participants
@gwuhaolin
Owner

gwuhaolin commented Jun 27, 2017

随着react、vue、angular等前端框架的流行越来越多的web应用变成了单页应用,它们的特点是异步拉取数据在浏览器中渲染出HTML。使用这些框架极大的提升web用户体验和开发效率的同时缺带来一个新问题,那就是这样的网页无法被搜索引擎收录。虽然这些web框架支持服务端渲染,但这可能又会增加开发成本。

有没有一个可用于任何单页应用的SEO解决方案,让我们不用对代码做改变保持原有的开发效率?chrome-render可以帮我们做到这点,它通过控制HeadlessChrome渲染出最终的HTML返回给爬虫来实现。

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。具体操作见文档:

chrome-render原理与实践

原理

chrome-render先会通过chrome-runner以headless模式启动和守护你操作上的chrome,再通过chrome-remote-interface操控chrome去访问需要被SEO的网页让chrome运行这个网页,等到包含数据的HTML被渲染出来时读取当前网页DOM转换成字符串后返回。

怎么知道你的网页什么时候已经渲染出包含数据的HTML了可以返回了呢?为了提升chrome-render效率,默认会在domContentEventFired时返回。对于复杂的场景还可以通过开启chrome-render的useReady选项,等到网页里调用了window.chromeRenderReady()时返回。

只渲染出了HTML还不够我们还需要检测出来着搜索引擎爬虫的访问,如果请求来着爬虫就返回chrome-render渲染后的HTML否则返回正常的单页应用所需HTML。

综上,整体架构如下:
koa-seo arch

实践

只需以下几行简单代码就可让chrome渲染出HTML:

const ChromeRender = require('chrome-render');
ChromeRender.new().then(async(chromeRender)=>{
    const htmlString = await chromeRender.render({
       url: 'http://qq.com',
    });
});    

chrome-render只是做了渲染出HTML的工作,要实现SEO还需要和web服务器集成。为了方便大家使用我做了一个koa中间件koa-seo,要集成到你现有的项目很简单,如下:

const seoMiddleware = require('koa-seo');
const app = new Koa();
app.use(seoMiddleware());

只需像这样接入一个中间件你的单页应用就被SEO了。

应用场景扩展

chrome-render除了用于通用SEO解决方案其实可以用于通用服务端渲染,因为目的都是渲染出最终的HTML再返回。针对通用服务端渲染我也做了一个koa中间件koa-chrome-render。使用chrome-render做服务端渲染的

优势在于:

  • 通用,适用于所有单页应用
  • 对原有代码几乎无改动,最多再合适的地方加个window.chromeRenderReady(),保持原有开发效率

缺点在于:

  • 和react、vue等只带的服务端渲染相比性能低(经我测试大约 200ms vs 60ms)
  • chrome-render渲染时占用资源高,一次渲染大约占用25Mb内存,当请求量大时服务器可能扛不住。但是可以通过缓存渲染结果优化。

总结

大家可能会说这个很像prerender.io,没错思路是一样的,chrome-render的优势在于:

  • chrome-render开源可自己部署,prerender要收费是商业产品
  • prerender基于已经停止维护的phantomjs

本文中所提到的相关项目都是开源的并且有详细的使用文档,它们的文档链接如下:

喜欢的给个star,希望大家和我一起来改进它们让它们更强大。

阅读原文

@deboyblog

This comment has been minimized.

Show comment
Hide comment

deboyblog commented Jun 29, 2017

@chenjunxyf

This comment has been minimized.

Show comment
Hide comment
@chenjunxyf

chenjunxyf Jun 30, 2017

赞~ 那如何检测是搜索引擎爬虫的访问呢?

chenjunxyf commented Jun 30, 2017

赞~ 那如何检测是搜索引擎爬虫的访问呢?

@gwuhaolin

This comment has been minimized.

Show comment
Hide comment
@gwuhaolin

gwuhaolin Jun 30, 2017

Owner

@chenjunxyf 检测是搜索引擎爬虫的访问是通过判断UA实现的。爬虫检测函数isCrawler https://github.com/gwuhaolin/koa-seo/blob/master/index.js#L35

Owner

gwuhaolin commented Jun 30, 2017

@chenjunxyf 检测是搜索引擎爬虫的访问是通过判断UA实现的。爬虫检测函数isCrawler https://github.com/gwuhaolin/koa-seo/blob/master/index.js#L35

@deboyblog

This comment has been minimized.

Show comment
Hide comment
@deboyblog

deboyblog Jun 30, 2017

@chenjunxyf 可以在 apache 或者 nginx 的配置中通过UA检测到
然后爬虫就转发到 render 服务
普通用户的 UA 是没有爬虫的信息的 就可以用SPA的模式正常渲染
比如 nginx 在站点的配置文件中

    if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
        set $isSpider 1;
    }

详情可以看我上面提到的文章 prerender 官方也提供了很多中间件 可以参考

deboyblog commented Jun 30, 2017

@chenjunxyf 可以在 apache 或者 nginx 的配置中通过UA检测到
然后爬虫就转发到 render 服务
普通用户的 UA 是没有爬虫的信息的 就可以用SPA的模式正常渲染
比如 nginx 在站点的配置文件中

    if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") {
        set $isSpider 1;
    }

详情可以看我上面提到的文章 prerender 官方也提供了很多中间件 可以参考

@gwuhaolin gwuhaolin added the chrome label Jun 30, 2017

@stjw7098

This comment has been minimized.

Show comment
Hide comment
@stjw7098

stjw7098 Jul 11, 2017

楼主你好,我想问下vue具体怎么用,就加上上面两段代码就可以了吗,整个项目只引入一次吗?

stjw7098 commented Jul 11, 2017

楼主你好,我想问下vue具体怎么用,就加上上面两段代码就可以了吗,整个项目只引入一次吗?

@gwuhaolin

This comment has been minimized.

Show comment
Hide comment
@gwuhaolin

gwuhaolin Jul 12, 2017

Owner

@stjw7098 chrome-render 的SEO方案可以用于如何网页,而且任何网页使用方法都是一样的,和网页使用的是React还是Vue没有任何关系。你需要大概明白它的原理才能灵活应用。

Owner

gwuhaolin commented Jul 12, 2017

@stjw7098 chrome-render 的SEO方案可以用于如何网页,而且任何网页使用方法都是一样的,和网页使用的是React还是Vue没有任何关系。你需要大概明白它的原理才能灵活应用。

@LeifJG

This comment has been minimized.

Show comment
Hide comment
@LeifJG

LeifJG Nov 8, 2017

这种方法会不会被百度视为作弊?

LeifJG commented Nov 8, 2017

这种方法会不会被百度视为作弊?

@gwuhaolin

This comment has been minimized.

Show comment
Hide comment
@gwuhaolin

gwuhaolin Nov 8, 2017

Owner

@LeifJG 不会,是百度自己无能不能收录单页应用,所以才做这个来兼容它。

Owner

gwuhaolin commented Nov 8, 2017

@LeifJG 不会,是百度自己无能不能收录单页应用,所以才做这个来兼容它。

@LeifJG

This comment has been minimized.

Show comment
Hide comment
@LeifJG

LeifJG Nov 8, 2017

感谢解答,还有一个问题,如果是多页面的vue可以使用这个方法吗,就是多个vue页面用链接的方式跳转的网站。

LeifJG commented Nov 8, 2017

感谢解答,还有一个问题,如果是多页面的vue可以使用这个方法吗,就是多个vue页面用链接的方式跳转的网站。

@donne1226

This comment has been minimized.

Show comment
Hide comment
@donne1226

donne1226 Nov 15, 2017

能不能写个demo?实在不知道怎么用。 因为写的是 移动端项目,一开始并没有要求SEO,现在写完了要做SEO,其实可以迁移到 nuxt.js。 但是需要成本。作者给个示例吧。 如果简单的话 就直接用了,万分感谢~

donne1226 commented Nov 15, 2017

能不能写个demo?实在不知道怎么用。 因为写的是 移动端项目,一开始并没有要求SEO,现在写完了要做SEO,其实可以迁移到 nuxt.js。 但是需要成本。作者给个示例吧。 如果简单的话 就直接用了,万分感谢~

@LvChengbin

This comment has been minimized.

Show comment
Hide comment
@LvChengbin

LvChengbin Jan 24, 2018

这种方法和判断爬虫之后输出一些同步内容没有什么不同,而且实现起来更麻烦,遇到频繁抓去的时候,也抗不下来吧。

LvChengbin commented Jan 24, 2018

这种方法和判断爬虫之后输出一些同步内容没有什么不同,而且实现起来更麻烦,遇到频繁抓去的时候,也抗不下来吧。

@taichiyi

This comment has been minimized.

Show comment
Hide comment
@taichiyi

taichiyi Mar 7, 2018

centos 6.5 下好像安装不了chrome ,那就没法用这个办法了吗?@gwuhaolin

taichiyi commented Mar 7, 2018

centos 6.5 下好像安装不了chrome ,那就没法用这个办法了吗?@gwuhaolin

@linw1995

This comment has been minimized.

Show comment
Hide comment

linw1995 commented Mar 7, 2018

@GavinFreedom

This comment has been minimized.

Show comment
Hide comment
@GavinFreedom

GavinFreedom Apr 27, 2018

楼主您好,我已经安装了chrom了
[root@izj6c1h8vqjcmblprak6fvz chrome-render]# chrome --version
Google Chrome 66.0.3359.117

但是项目在运行的时候提示
Error: chrome-render timeout
at Object. (/data/www/novel-nodeServer/node_modules/chrome-render/index.js:6:28)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object. (/data/www/novel-nodeServer/node_modules/express-middleware-seo/core.js:2:22)
at Module._compile (module.js:652:30)
No Chrome environment, please install Chrome 59+!

请问怎么解决

GavinFreedom commented Apr 27, 2018

楼主您好,我已经安装了chrom了
[root@izj6c1h8vqjcmblprak6fvz chrome-render]# chrome --version
Google Chrome 66.0.3359.117

但是项目在运行的时候提示
Error: chrome-render timeout
at Object. (/data/www/novel-nodeServer/node_modules/chrome-render/index.js:6:28)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Module.require (module.js:596:17)
at require (internal/module.js:11:18)
at Object. (/data/www/novel-nodeServer/node_modules/express-middleware-seo/core.js:2:22)
at Module._compile (module.js:652:30)
No Chrome environment, please install Chrome 59+!

请问怎么解决

@LvChengbin

This comment has been minimized.

Show comment
Hide comment
@LvChengbin

LvChengbin Apr 27, 2018

@GavinFreedom 这个为什么要来这里问。可以看下 https://github.com/GoogleChrome/puppeteer

LvChengbin commented Apr 27, 2018

@GavinFreedom 这个为什么要来这里问。可以看下 https://github.com/GoogleChrome/puppeteer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment