用PhantomJS來給AJAX站點做SEO優化

轉 https://www.mxgw.info/t/phantomjs-prerender-for-seo.html

 

騰訊問卷所有動態內容,全部由Ajax接口提供。

衆所周知,大部分的搜索引擎爬蟲都不會執行JS,也就是說,如果頁面內容由Ajax返回的話,搜索引擎是爬取不到部分內容的,也就無從做SEO了。

先來看看效果

QQ20160321-1

去年一整年,搜索引擎收錄都少得可憐。

更致命的是,被收錄的頁面,其搜索引擎裏面顯示的標題是最原始的html標題,權重如此高的地方,卻被收錄了一個沒什麼用的標題。

在去年年底完成實施了預渲染服務後,收錄量蹭蹭蹭的起來了,並且收錄的標題也都全部正常了。

而這所有的一切,除了Nginx接入層的配置是需要改動業務代碼外,其他全部都是旁路機制。也就是說,自己做一套,可以給所有同類型業務共用,同時不會影響現有業務的任何代碼任何流程。

 

PhantomJS來解圍

Ajax無法做SEO這個問題,困擾了我很久,後來發現PhantomJS這東西能在服務端解析HTML,瞬間這個問題不再是問題。

PhantomJS is a headless WebKit scriptable with a JavaScript API. It has fast andnativesupport for various web standards: DOM handling, CSS selector, JSON, Canvas, and SVG.

準備一個PhantomJS任務腳本

這裏我命名爲spider.js。

  /*global phantom*/
  "use strict";
   
  // 單個資源等待時間,避免資源加載後還需要加載其他資源
  var resourceWait = 500;
  var resourceWaitTimer;
   
  // 最大等待時間
  var maxWait = 5000;
  var maxWaitTimer;
   
  // 資源計數
  var resourceCount = 0;
   
  // PhantomJS WebPage模塊
  var page = require('webpage').create();
   
  // NodeJS 系統模塊
  var system = require('system');
   
  // 從CLI中獲取第二個參數爲目標URL
  var url = system.args[1];
   
  // 設置PhantomJS視窗大小
  page.viewportSize = {
  width: 1280,
  height: 1014
  };
   
  // 獲取鏡像
  var capture = function(errCode){
   
  // 外部通過stdout獲取頁面內容
  console.log(page.content);
   
  // 清除計時器
  clearTimeout(maxWaitTimer);
   
  // 任務完成,正常退出
  phantom.exit(errCode);
   
  };
   
  // 資源請求並計數
  page.onResourceRequested = function(req){
  resourceCount++;
  clearTimeout(resourceWaitTimer);
  };
   
  // 資源加載完畢
  page.onResourceReceived = function (res) {
   
  // chunk模式的HTTP回包,會多次觸發resourceReceived事件,需要判斷資源是否已經end
  if (res.stage !== 'end'){
  return;
  }
   
  resourceCount--;
   
  if (resourceCount === 0){
   
  // 當頁面中全部資源都加載完畢後,截取當前渲染出來的html
  // 由於onResourceReceived在資源加載完畢就立即被調用了,我們需要給一些時間讓JS跑解析任務
  // 這裏默認預留500毫秒
  resourceWaitTimer = setTimeout(capture, resourceWait);
   
  }
  };
   
  // 資源加載超時
  page.onResourceTimeout = function(req){
  resouceCount--;
  };
   
  // 資源加載失敗
  page.onResourceError = function(err){
  resourceCount--;
  };
   
  // 打開頁面
  page.open(url, function (status) {
   
  if (status !== 'success') {
   
  phantom.exit(1);
   
  } else {
   
  // 當改頁面的初始html返回成功後,開啓定時器
  // 當到達最大時間(默認5秒)的時候,截取那一時刻渲染出來的html
  maxWaitTimer = setTimeout(function(){
   
  capture(2);
   
  }, maxWait);
   
  }
   
  });
view rawspider.js hosted with  by GitHub

通過PhantomJS命令直接執行即可在終端中看到渲染後的html結構

 

命令服務化

什麼意思呢,因爲上面是一個命令,沒法很好的響應搜索引擎爬蟲的請求,估我們要把他服務化。

PhantomJS自帶一個Web Server Module,但總是不穩定,如前面文章所說時不時會假死。

我們就通過Node給他起一個簡單的Web服務。

  // ExpressJS調用方式
  var express = require('express');
  var app = express();
   
  // 引入NodeJS的子進程模塊
  var child_process = require('child_process');
   
  app.get('/', function(req, res){
   
  // 完整URL
  var url = req.protocol + '://'+ req.hostname + req.originalUrl;
   
  // 預渲染後的頁面字符串容器
  var content = '';
   
  // 開啓一個phantomjs子進程
  var phantom = child_process.spawn('phantomjs', ['spider.js', url]);
   
  // 設置stdout字符編碼
  phantom.stdout.setEncoding('utf8');
   
  // 監聽phantomjs的stdout,並拼接起來
  phantom.stdout.on('data', function(data){
  content += data.toString();
  });
   
  // 監聽子進程退出事件
  phantom.on('exit', function(code){
  switch (code){
  case 1:
  console.log('加載失敗');
  res.send('加載失敗');
  break;
  case 2:
  console.log('加載超時: '+ url);
  res.send(content);
  break;
  default:
  res.send(content);
  break;
  }
  });
   
  });
view rawexpress_spider.js hosted with  by GitHub

旁路服務

我們現在已經有了一個能跑預渲染的Web服務了,剩下就是要將搜索引擎爬蟲的流量導入到這個預渲染的服務中,同時把結果再返回給搜索引擎爬蟲。

我們使用Nginx這個接入層利器即可輕鬆解決這個問題。

  # 定義一個Nginx的upstream爲spider_server
  upstream spider_server {
  server localhost:3000;
  }
   
  # 指定一個範圍,默認 / 表示全部請求
  location / {
  proxy_set_header Host $host:$proxy_port;
  proxy_set_header X-Real-IP $remote_addr;
  proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   
  # 當UA裏面含有Baiduspider的時候,流量Nginx以反向代理的形式,將流量傳遞給spider_server
  if ($http_user_agent ~* "Baiduspider") {
  proxy_pass http://spider_server;
  }
  }
view rawnginx_spider.conf hosted with  by GitHub

這個栗子裏面僅僅對百度爬蟲做了處理,可以自行把爬蟲都補完整。

Free

說了這麼多,我突然覺得這篇文章非常值錢。

因爲,國外也有專門的服務端預渲染服務了,但他們統統要收費。

你可以根據本文的思路,自行部署一套旁路渲染服務。

附上一份新鮮收集的爬蟲UA列表

  • 360 【文檔】
    • 360Spider
    • HaoSouSpider
    • 360Spider-Image
    • 360Spider-Video
  • Baidu 【文檔】
    • Baiduspider
  • Google 【文檔】
    • Googlebot
    • Googlebot-News
    • Googlebot-Video
    • Googlebot-Mobile
  • Sogou 【文檔】
    • Sogou web spider
    • Sogou inst spider
    • Sogou Spider
  • Bingbot【文檔
    • bingbot
    • msnbot
    • msnbot-media
    • adidxbot
    • BingPreview
發佈了347 篇原創文章 · 獲贊 8 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章