使用Node.js制作爬蟲教程
來自: http://blog.didispace.com/nodejspachong/
應邀寫一點使用Node.js爬點資料的實例,對于大家建站爬一些初始資料或者做分析研究的小伙伴們應該有些幫助。
</div>
目標分析
目標地址: http://wcatproject.com/charSearch/
抓取內容:抓取所有4星角色的數值數據。如果我們采用手工采集的步驟,需要先進入目標地址,然后選擇4星角色的選項,頁面下方出現所有4星角色的頭像,依次點擊每個4星角色頭像后會出現角色的詳細頁面,記錄下詳細頁面中數據。顯然這樣的做法如果角色一多,手工處理是非常吃力的,所以我們就需要一個自動的腳本去完成這樣的動作。大家不妨先手工試試這樣的訪問步驟,有助于后面的分析和實踐。
頁面分析:
- 進入 http://wcatproject.com/charSearch/
- 打開Chrome的“開發者工具”,選擇“Network”標簽。點亮“Record Network Log”按鈕
- 第一步頁面操作:在頁面中“星數”選擇“4”,查詢出所有4星角色,觀察Network中記錄的請求信息。可以看到一個名為“getData.php”的請求,如圖所示:
- getData.php中的重要信息記錄(通過nodejs發起請求時候需要)
4.1 Request URL 我們需要調用的請求地址: http://wcatproject.com/charSearch/function/getData.php
4.2 Request Method 該請求的類型:POST
4.3 Request Header 請求的頭信息
4.4 Form Data 請求的表單信息
4.5 Response 和 Preview 中可以看到返回的內容和格式化內容,可以看到返回的是一個角色ID和角色名稱的數組內容
4.6 在“開發者工具”中選擇“Elements”標簽,點擊左上角的放大鏡,將鼠標移到下方伙伴的頭像部分點擊鼠標左鍵,可以看到這塊的HTML結構。可以看到每個角色的鏈接的規則為 char/角色id
- 第二部頁面操作:點擊頁面下面查詢出的4星角色的頭像,進入到角色詳細頁面,觀察Network中記錄的請求信息。可以找到一個名為“SS0441”的請求,如上步驟,記錄下相關信息,由于這個請求的 Request Method 為GET,因此沒有Form Data信息。
最后在理一下思路,我們的腳本過程如下:
- 發起getData.php請求,獲得所有4星角色的ID
- 依次循環根據 char/角色id 規則訪問各個角色的詳細頁面,并解析其中需要的數據并按我們想要的方式存儲起來
準備工作
- Node.js環境搭建
- 一款具有代碼高亮功能文本編輯器,如Sublime Text等
- 使用nvm工具將Node.js版本設置為5.0.0
創建工程
- 選擇一個目錄,新建一個準備存放工程內容的文件夾demo。
- 打開終端(windows機器打開CMD命令行),輸入 npm init ,根據提示,逐步輸入工程信息,具體示例如下
$ npm init This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.See
npm help jsonfor definitive documentation on these fields
and exactly what they do.Use
npm install <pkg> --saveafterwards to install a package and
save it as a dependency in the package.json file.Press ^C at any time to quit.
name: (workspace) demo
version: (1.0.0)
description: 爬蟲案例
entry point: (index.js)
test command:
git repository:
keywords:
author: 程序猿DD
license: (ISC)
About to write to /Users/diyongchao/Documents/workspace/package.json:{ "name": "demo", "version": "1.0.0", "description": "爬蟲案例", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "程序猿DD", "license": "ISC" }
Is this ok? (yes) yes
$</pre>
- 此時文件夾下生成了一個 package.json 文件,其中包含了工程的基本信息以及引用的框架等信息
- superagent :發起http請求
- cheerio :解析http返回的html內容
- async :多線程并發控制
</ul>
框架引入
安裝命令 npm install --save PACKAGE_NAME ,執行以下三條命令后,工程目錄下多了一個 node_modules 目錄,該目錄就是引入的框架內容。
$npm install --save superagent $npm install --save cheerio $npm install --save async
編碼過程
工程目錄下,創建index.js
var superagent = require('superagent');
var cheerio = require('cheerio');
var async = require('async');
console.log('爬蟲程序開始運行......');
// 第一步,發起getData請求,獲取所有4星角色的列表
superagent
.post('/; q=0.01')
.set('Content-Type','application/x-www-form-urlencoded; charset=UTF-8')
.end(function(err, res){
// 請求返回后的處理
// 將response中返回的結果轉換成JSON對象
var heroes = JSON.parse(res.text);
// 并發遍歷heroes對象
async.mapLimit(heroes, 1,
function (hero, callback) {
// 對每個角色對象的處理邏輯
var heroId = hero[0]; // 獲取角色數據第一位的數據,即:角色id
fetchInfo(heroId, callback);
},
function (err, result) {
console.log('抓取的角色數:' + heroes.length);
}
);
});
// 獲取角色信息
var concurrencyCount = 0; // 當前并發數記錄
var fetchInfo = function(heroId, callback){
concurrencyCount++;
// console.log("...正在抓取"+ heroId + "...當前并發數記錄:" + concurrencyCount);
// 根據角色ID,進行詳細頁面的爬取和解析
superagent
.get('http://wcatproject.com/char/' + heroId)
.end(function(err, res){
// 獲取爬到的角色詳細頁面內容
var $ = cheerio.load(res.text,{decodeEntities: false});
// 對頁面內容進行解析,以收集隊長技能為例,此處可根據自己的需要進行寫數據等操作來記錄收集的信息
console.log(heroId + '\t' + $('.leader-skill span').last().text())
concurrencyCount--;
callback(null, heroId);
});
};</pre>
工程目錄下執行命令, node index.js ,抓取程序開始執行
$ node index.js
爬蟲程序開始運行......
SS0441 平衡型傷害增加 (20%)
NS1641 防禦型的移速增加 (20%)
SS1141 技術型的技能傷害增加 (20%)
SS1041 攻擊型的SP增加 (15%)
SS0941 攻擊型傷害增加 (20%)
SS0841 劍士減傷 (10%) / 技術型減傷 (15%)
LS0941 全員傷害增加 (15%)
LS1441 劍士傷害增加 (10%) / 技術型傷害增加 (15%)
SS0741 劍士雷屬性傷害增加 (50%)
SS0641 攻擊型傷害增加 (20%)
NS1741 技能型的SP消費減少 (15%)
NS1141 全員傷害增加 (15%)
NS0031-A 獲得的魂增加 (20%)
SS0501 技術型傷害增加 (20%)
SS0141 劍士傷害增加 (20%)
SS0241 全員傷害增加 (15%)
后記
如果覺得爬的慢,可以通過修改 async.mapLimit(heroes, 1, function (hero, callback) 中的1來調整并發數量,同時也可以去掉// console.log("...正在抓取"+ heroId + "...當前并發數記錄:" + concurrencyCount);的注釋,用來觀察執行過程中并發數。
如果對示例有疑問,歡迎留言交流^_^
</div>