Node爬蟲 爬博客園搜索

博客園右邊有一個「找找看」的索引窗口,咱們輸入關鍵詞,能夠查到幾萬篇的相關的博客,這裏用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 就起到了這個計數器的做用,它來幫你管理到底這些異步操做是否完成,完成以後,它會自動調用你提供的處理函數,並將抓取到的數據當參數傳過來。

相關文章
相關標籤/搜索