博客園右邊有一個「找找看」的索引窗口,咱們輸入關鍵詞,能夠查到幾萬篇的相關的博客,這裏用Node的爬蟲來抓取給定關鍵詞的查詢的特定內容,實現翻頁功能,抓取文章連接,做者,發佈日期等信息。html
Node適合高併發IO操做的程序,用來寫爬蟲速度最快了。這裏咱們把爬到的數據存儲到數據庫中。node
1.cheerio模塊 ,一個相似jQuery的選擇器模塊,分析HTML利器。mysql
2.request模塊,讓http請求變的更加簡單sql
3.mysql模塊,node鏈接mysql的模塊,可參考:http://www.runoob.com/nodejs/nodejs-mysql.html。數據庫
4.數據庫部分:編程
結構已經比較清晰併發
這裏的URL地址欄明文顯示的結構,中文是顯示出現了,可是實際URL內容是通過編碼了,複製地址欄內容,粘貼過來,咱們發現http://zzk.cnblogs.com/s/blogpost?Keywords=%E6%B8%B8%E6%88%8F,遊戲其實被編碼成了%E6%B8%B8%E6%88%8F,咱們這裏:異步
var url = 'http://zzk.cnblogs.com/s/blogpost?Keywords=' + key + '&pageindex=' + page;若是key是中文,是會抓取不到任何數據,用JS函數url = encodeURI(url);轉換一下就好。async
用"pageindex="出現的位置加上自己長度即獲得頁數ide
page = nextUrl.slice(nextUrl.indexOf('pageindex=') + 10);
indexof是返回子串在母串的第一個位置,沒有則-1,區分大小寫,slice也是從start取到end,注意下標1就是1開始,不是0
參考方法:http://www.w3school.com.cn/jsref/jsref_indexOf.asp
http://www.w3school.com.cn/jsref/jsref_slice_array.asp
var request = require('request'); var cheerio = require('cheerio'); var mysql = require('mysql'); var db = mysql.createConnection({ host: '127.0.0.1', user: 'root', password: '123456', database: 'spider_data' }); db.connect(); function fetchData(key, page) { var url = 'http://zzk.cnblogs.com/s/blogpost?Keywords=' + key + '&pageindex=' + page; //用JS的全局對象函數,做爲URI編碼,否則中文,空格等抓取不到 url = encodeURI(url); request(url, function(err, res) { if (err) return console.log(err); var $ = cheerio.load(res.body.toString()); var arr = []; //解析HTML代碼 $('.searchItem').each(function() { var title = $(this).find('.searchItemTitle'); var author = $(this).find('.searchItemInfo-userName a'); var time = $(this).find('.searchItemInfo-publishDate'); var view = $(this).find('.searchItemInfo-views'); var info = { title: $(title).find('a').text(), href: $(title).find('a').attr('href'), author: $(author).text(), time: $(time).text(), view: $(view).text().replace(/[^0-9]/ig, '') }; arr.push(info); //打印 console.log('~~~~~~~~~~~~~~~~~~~~~~~ 輸出開始 ~~~~~~~~~~~~~~~~~~~~~~~'); console.log(info); console.log('~~~~~~~~~~~~~~~~~~~~~~~ 輸出結束 ~~~~~~~~~~~~~~~~~~~~~~~'); //保存數據 db.query('insert into blog set ?', info, function(err, result) { if (err) throw err; if (!!result) { console.log('插入成功'); console.log(result.insertId); } else { console.log('插入失敗'); } }); }); //下一頁 var nextA = $('.pager a').last(), nextUrl = ''; if ($(nextA).text().indexOf('Next') != -1) { nextUrl = nextA.attr('href'); page = nextUrl.slice(nextUrl.indexOf('pageindex=') + 10);//"pageindex="出現的位置加上自己長度獲得頁數 setTimeout(function() { fetchData(key, page); }, 2000); } else { db.end(); console.log('結束,爬取完全部數據'); } }); } fetchData('遊戲開發', 1);
咱們能夠隨意換關鍵詞,清空這個數據表。
速度太多,可能會被封IP,咱們在後續能夠用async 模塊控制,async是一個流程控制工具包,提供了直接而強大的異步功能,進而在爬取頁面時控制併發數。
用eventproxy 帶來一種事件式編程的變化,若是你是要抓取多個源的數據,因爲你根本不知道這些異步操做到底誰先完成,那麼每次當抓取成功的時候,就須要判斷一下count === n。當值爲真時,使用另外一個函數繼續完成操做。而 eventproxy 就起到了這個計數器的做用,它來幫你管理到底這些異步操做是否完成,完成以後,它會自動調用你提供的處理函數,並將抓取到的數據當參數傳過來。