在网站页面后端渲染的时代,开发者只须要按照规范制做搜索引擎友好的页面即可以快速让搜索引擎收录本身网站的各个页面。css
随着先后端技术的更新,愈来愈多的前端框架进入开发者们的视野,网站的先后分离架构愈来愈获得开发者们的喜好与承认。 后端只提供数据接口、业务逻辑与持久化服务,而视图、控制与渲染则交给前端。 所以,愈来愈多的网站从后端渲染变成了前端渲染,而由此带来的直接问题就是各大搜索引擎爬虫对于前端渲染的页面( 动态内容 )还没法比较完善的爬取,这就致使了网站的内容没法被搜索引擎收录,直接影响网站流量与曝光度。前端
博主的网站从去年五月开始也开始采用了先后分离的构架,使用了 AngularJS 框架搭建了 NewRaPo , 以后又使用 Vue.js 框架进行了总体重构 RaPo3。 无一例外,他们都是基于前端渲染的,而后在此后的一年多时间里,搜索引擎收录的页面都是这样的:vue
( 其余搜索引擎也同样,最先的截图已经找不到了,先拿这个应付一下 )nginx
快照是这样的:git
而博主实际的网站是这样的:angularjs
和这样的:github
感受彻底被搜索引擎抛弃了好嘛!这东西谁能搜到啊!搜到了谁会点啊!web
为了能让搜索引擎正常的收录博主的网站,因而博主踏上了动态 SEO 优化的踩坑之路:shell
首先,博主 Google 到了在动态页面中加入 <meta name="fragment" content="!">
会告诉爬虫这是个动态内容的页面,而后爬虫会在当前连接后面加上 ?_escaped_fragment_=tag
来获取相应页面的静态版,因而果断盘算在路由里改一下,而后重写一套后端渲染的页面返回给全部带 ?_escaped_fragment_=tag
的连接。django
正当我高兴这个问题这么容易解决的时候忽然发现网上资料都表示这个方法只有 Google 的爬虫承认,其余搜索引擎所有没用! wtf,白高兴一场。
PhantomJS 是一个基于 WebKit 的服务器端 JavaScript API。它全面支持web而不需浏览器支持,其快速,原生支持各类Web标准: DOM 处理, CSS 选择器, JSON, Canvas, 和 SVG。 PhantomJS 能够用于 页面自动化 , 网络监测 , 网页截屏 ,以及 无界面测试 等
简单来讲就是 PhantomJS 能在服务端解析HTML、js。
具体怎么使用,简而言之就是判断爬虫来爬取页面的时候把每一个动态页面先让 PhantomJS 跑一遍,而后把获得的静态结果返回给爬虫,具体过程能够参考:用PhantomJS来给AJAX站点作SEO优化
固然博主看过以后没用采用本身搭 PhantomJS 服务作动态内容优化,主要由于:
爬虫每访问一个页面就要让 PhantomJS 渲染一次,至关于爬虫访问一次实际服务器要响应两次,第一次响应爬虫,第二次响应 PhantomJS 本身,这种方式不只浪费资源,并且并不优雅;
PhantomJS 对于新的前端技术兼容性会存在问题,可能会出现渲染失败的状况;
渲染页面无缓存,每访问一次就从新渲染一次,会形成网站响应速度变慢。
Prerender.io 是一个基于 PhantomJS 开发的专为动态页面 SEO 提供静态页面渲染的在线服务,基本上解决了本身搭建 PhantomJS 服务所遇到的问题,网站配置 Prerender.io 后 Prerender 将会直接取代网站后端对爬虫请求进行响应,将提早渲染好的动态页面直接返回给爬虫。
具体配置:
注册 Prerender.io 帐号,免费用户能够渲染 250 个页面,对于博客网站来讲足够了;
安装中间件并设置 token,博主直接采用了 nginx 配置方案,( Prerender.io 也提供了其余解决方案:https://prerender.io/document... )博主后端服务器是 uWSGI, 根据 Prerender.io 提供的 nginx.conf 中作以下修改:
server { listen 80; server_name www.rapospectre.com; location @prerender { proxy_set_header X-Prerender-Token YOUR_TOKEN; include uwsgi_params; set $prerender 0; if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") { set $prerender 1; } if ($args ~ "_escaped_fragment_") { set $prerender 1; } if ($http_user_agent ~ "Prerender") { set $prerender 0; } if ($uri ~* "\.(js|css|xml|less|png|jpg|jpeg|gif|pdf|doc|txt|ico|rss|zip|mp3|rar|exe|wmv|doc|avi|ppt|mpg|mpeg|tif|wav|mov|psd|ai|xls|mp4|m4a|swf|dat|dmg|iso|flv|m4v|torrent|ttf|woff|svg|eot)") { set $prerender 0; } #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs resolver 8.8.8.8; if ($prerender = 1) { #setting prerender as a variable forces DNS resolution since nginx caches IPs and doesnt play well with load balancing set $prerender "service.prerender.io"; rewrite .* /$scheme://$host$request_uri? break; proxy_pass http://$prerender; } if ($prerender = 0) { uwsgi_pass 127.0.0.1:xxxx; } } }
而后重启服务器,经过 Google Search Console 或其余站长工具提交页面进行爬取检测,能够看到,Prerender.io 成功截取了爬虫请求并进行了渲染:
嗯,终于解决了嘛,正当博主感叹不容易的时候,Google Search Console 的抓取结果却让人发现然并卵:
抓取的内容依然是满满的 ${ article.views }}
渲染模版,当时我认为应该是网站缓存的问题,因此没有多想,然而一周后再次测试,状况依旧,回头再看 Prerender 渲染的网页:
原来压根没起做用!以后又检查了配置和文档,尝试联系了 Prerender.io 的技术支持甚至向 Prerender 的 Github 提了相关 issue,都没有解决问题。 最后,不得已博主仍是放弃了 Prerender。
Prerender 的方案启发了我,经过判断来访请求的 User-Agent 来让不一样的后端服务器进行响应,虽然网上关于 SEO 优化的讨论中明确提到过判断 UA 返回不一样页面将会获得搜索引擎的惩罚,但我猜想这只是返回不一样内容才会惩罚,若是返回的是相同的内容搜索引擎就不会进行惩罚,区别在于一个是直接经过前端渲染的页面,而另外一个则是后端渲染的页面,两个页面渲染出的内容基本相同,那么搜索引擎就不会发现。
本身动手,丰衣足食,有了想法当即验证,首先把网站代码中前端渲染的部分改成后端渲染,而后 push 到一个新的分支,博主网站修改十分简单,大概只修改了 50 行不到的代码就完成了需求: RaPo3-Shadow
接着将后端渲染代码部署到服务器,而后假设用 uWSGI 将它跑在 11011 端口,
此时前端渲染的代码由 uWSGI 假设跑在 11000 端口;
最后修改 nginx 配置文件 nginx.conf:
server { listen 80; server_name www.rapospectre.com; location @prerender { include uwsgi_params; set $prerender 0; if ($http_user_agent ~* "baiduspider|twitterbot|facebookexternalhit|rogerbot|linkedinbot|embedly|quora link preview|showyoubot|outbrain|pinterest|slackbot|vkShare|W3C_Validator") { set $prerender 1; } #resolve using Google's DNS server to force DNS resolution and prevent caching of IPs resolver 8.8.8.8; if ($prerender = 1) { uwsgi_pass 127.0.0.1:11011; } if ($prerender = 0) { uwsgi_pass 127.0.0.1:11000; } } }
就是经过 UA 判断爬虫,若是是则转发给 11011 端口,不是就转发给 11000 端口,固然两个端口返回的页面基本是相同的,因此也就不用担忧会被搜索引擎惩罚了。
经过以上配置后,动态页面的 SEO 问题终于获得了解决,反应最快的是 Google,次日就爬取并更新到了搜索引擎:
接着 360 搜索:
而后其余没有提交过网址的搜索引擎也分分收录了网站:
( bing 没有收录正常的页面应该是因为 nginx.conf 里没有加入 bing 爬虫 UA 的缘故 )
固然,不知道什么缘由百度过了两个多月仍是没有收录,在站长工具中提交网页甚至申诉都没有收录新的网页。没错,开头那个用来应付一下的图片就是百度的结果,刚截的。
我该说幸亏没更新,不然找不到之前的例子了嘛,哈哈哈哈。
经过博主本身搭建后端渲染服务已经解决了动态页面 SEO 优化问题,但博主还有一个可行办法的猜测,不知是否可行,写在这里若是看了以上办法都很差用的朋友能够试试。
canonical 标签是 Google 、雅虎、微软等搜索引擎一块儿推出的一个标签,它的主要做用是用来解决因为网址形式不一样内容相同而形成的内容重复问题。 这个标签的制定时间已经好久了,因此如今主流的搜索引擎都支持这个标签,它本来的做用是将 url 不一样但内容相同的网址权重所有集中到其中一个网址上,这样能够避免大量重复内容网页被搜索引擎收录,举个例子:
http://www.rapospectre.com/archives/1 http://www.rapospectre.com/archives/1?comments=true http://www.rapospectre.com/archives/1?postcomment=true
这三个网址的内容其实彻底同样,为了不重复收录和分权,在原始网页加上 <link rel='canonical' href='http://www.rapospectre.com/archives/1' />
这样其余重复网页将被看做都是 http://www.rapospectre.com/archives/1
那么假设对于动态网页 http://www.rapospectre.com/dynamic/1
,咱们编写他的静态网页:http://www.rapospectre.com/static/1
, 而后在 http://www.rapospectre.com/dynamic/1
的页面内加入: <link rel='canonical' href='http://www.rapospectre.com/static/1
, 这样是否也能达到动态 SEO 优化的目的呢?
随着前端渲染的页面愈来愈多,动态页面的 SEO 优化逐渐进入人们的视野,博主将本身动态页面的 SEO 优化经历写出,但愿能帮到其余注意到这个领域或遇到相同问题的人,提供一些思路。 谢谢。
做者:rapospectre