????在上一篇文章(VUE(SPA)項目中使用SEO-流程及原理分析)提到過,想要搜索引擎的爬蟲過來可以爬取到你網(wǎng)站的內(nèi)容需要用到
由于PhantomJS已不再維護,本篇文章將最新方法放到下方W钐!!
node.js励翼、Nginx废菱、
PhantomJS(已經(jīng)不維護奕巍,放棄)、puppeteer(代替PhantomJS)
? ? 那么這篇文章將會詳細的說一下它們的使用方法棠绘。(此處放一張圖,幫大家回顧一下整個流程)
????利用Nginx就是用來區(qū)分這次請求是來自爬蟲、還是用戶氧苍,如果是用戶就直接返回給頁面就好了夜矗。
? ? 這里 node.js 是做了個啟動PhantomJS的作用,具體代碼如下:
// server.js
// ExpressJS調(diào)用方式
var express = require('express');
var app = express();
var path = process.cwd();
// 引入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', [path + '/spider.js', url]);
? ? // 設置stdout字符編碼
? ? phantom.stdout.setEncoding('utf8');
? ? // 監(jiān)聽phantomjs的stdout让虐,并拼接起來
? ? phantom.stdout.on('data', function(data){
? ? ? ? content += data.toString();
? ? });
? ? // 監(jiān)聽子進程退出事件
? ? phantom.on('exit', function(code){
? ? ? ? switch (code){
? ? ? ? ? ? case 1:
? ? ? ? ? ? ? ? console.log('加載失敗');
? ? ? ? ? ? ? ? res.send('加載失敗');
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case 2:
? ? ? ? ? ? ? ? console.log('加載超時: '+ url);
? ? ? ? ? ? ? ? res.send(content);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? console.log('加載頁面: '+ url);
? ? ? ? ? ? ? ? res.send(content);
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? });
});
app.listen(3000, function () {
? console.log('Spider app listening on port 3000!');
? console.log(path + '/spider.js')
});
利用這個node服務就可以調(diào)用到PhantomJS啦紊撕,PhantomJS的代碼如下:
/*global phantom*/
"use strict";
// 單個資源等待時間,避免資源加載后還需要加載其他資源
var resourceWait = 500;
var resourceWaitTimer;
// 最大等待時間
var maxWait = 5000;
var maxWaitTimer;
// 資源計數(shù)
var resourceCount = 0;
// PhantomJS WebPage模塊
var page = require('webpage').create();
// NodeJS 系統(tǒng)模塊
var system = require('system');
// 從CLI中獲取第二個參數(shù)為目標URL
var url = system.args[1];
// 設置PhantomJS視窗大小
page.viewportSize = {
? ? width: 1280,
? ? height: 1014
};
// 獲取鏡像
var capture = function(errCode){
? ? // 外部通過stdout獲取頁面內(nèi)容
? ? console.log(page.content);
? ? // 清除計時器
? ? clearTimeout(maxWaitTimer);
? ? // 任務完成赡突,正常退出
? ? phantom.exit(errCode);
};
// 資源請求并計數(shù)
page.onResourceRequested = function(req){
? ? resourceCount++;
? ? clearTimeout(resourceWaitTimer);
};
// 資源加載完畢
page.onResourceReceived = function (res) {
? ? // chunk模式的HTTP回包对扶,會多次觸發(fā)resourceReceived事件,需要判斷資源是否已經(jīng)end
? ? if (res.stage !== 'end'){
? ? ? ? return;
? ? }
? ? resourceCount--;
? ? if (resourceCount === 0){
? ? ? ? // 當頁面中全部資源都加載完畢后惭缰,截取當前渲染出來的html
? ? ? ? // 由于onResourceReceived在資源加載完畢就立即被調(diào)用了浪南,我們需要給一些時間讓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返回成功后,開啟定時器
? ? ? ? // 當?shù)竭_最大時間(默認5秒)的時候漱受,截取那一時刻渲染出來的html
? ? ? ? maxWaitTimer = setTimeout(function(){
? ? ? ? ? ? capture(2);
? ? ? ? }, maxWait);
? ? }
});
????這里面注釋寫的比較詳細络凿,可以看到這個文件實際上就是模擬一個瀏覽器窗口,從而獲取到頁面內(nèi)容昂羡,這樣爬蟲來了喷众,我們就把這個文件獲取到的頁面內(nèi)容甩給它就行了。
? ? 接下來進入測試階段紧憾,先測試下PhantomJS是否OK??
$ phantomjs spider.js 'http://www.baidu.com'
如果見到在命令行里出現(xiàn)了一推html到千,那恭喜你,你已經(jīng)征服PhantomJS啦赴穗。
一切都準備就緒之后憔四,需要整體測試一次,可以用Postman這個工具發(fā)起測試
如果看到了你的內(nèi)容般眉,那么恭喜你了赵,你已經(jīng)征服它們啦。
2021.1.13日更新:
由于PhantomJS已不再維護甸赃,如果用PhantomJS抓一些普通的頁面還可以用柿汛,但是抓SPA項目已經(jīng)不好用了,下面推薦一個node爬蟲工具(puppeteer)來替代PhantomJS
首先我們用npm來安裝:
npm install puppeteer
然后將上面的PhantomJS服務改為node服務埠对,代碼如下:
var url = process.argv.splice(2)[0];
const puppeteer = require('puppeteer');
async function run(params) {
? ? const browser = await puppeteer.launch();
? ? const page = await browser.newPage();
? ? await page.goto(url, {
? ? ? ? waitUntil: 'load', // Remove the timeout
? ? ? ? timeout: 0
? ? });
? ? const html = await page.content();
? ? console.log(html);
? ? process.exit();
}
process.on('exit', function(code) {
? ? process.exit();
});
run()络断;
然后再命令行工具中運行(如我的node.js文件名為spider.js):
?node spider.js http://xxxx.com
測試后會在命令行里輸出爬取到的HTML文本。
還有一點要注意一下项玛,別忘了把上面的啟動命令改掉:
原:
child_process.spawn('phantomjs', [path + '/spider.js', url]);
改為:
child_process.spawn('node', [path + '/spider.js', url]);
如果有小伙伴遇到這篇文章相關的SEO的問題貌笨,可以隨時私信我!=缶凇锥惋!