nodejs網(wǎng)絡(luò)爬蟲(chóng)技術(shù)詳解

現(xiàn)在是大數(shù)據(jù)的時(shí)代,網(wǎng)絡(luò)上現(xiàn)成的數(shù)據(jù)都在那里,就看你怎么樣來(lái)利用,網(wǎng)絡(luò)爬蟲(chóng),最適合來(lái)抓取我們需要的數(shù)據(jù)。
那用nodejs來(lái)完成整個(gè)爬蟲(chóng)我們需要哪些模塊和技術(shù)呢

1.request模塊
request是一個(gè)用來(lái)簡(jiǎn)化HTTP請(qǐng)求操作的模塊,其功能強(qiáng)大而且使用方法簡(jiǎn)單
具體用法可以參考
http://blog.youlunshidai.com/post?id=91

2.cheerio模塊
相信用nodejs做過(guò)網(wǎng)絡(luò)爬蟲(chóng)的小伙伴們都知道cheerio這個(gè)模塊,是的,他是jQuery Core的子集,其實(shí)現(xiàn)了jQuery Core中瀏覽器無(wú)關(guān)的DOM操作API,一般通過(guò)cheerio.load方法來(lái)加載我們通過(guò)http請(qǐng)求到的網(wǎng)頁(yè)內(nèi)容,然后進(jìn)行DOM操作,抓取我們需要的數(shù)據(jù)。
需要注意的是,cheerio并不支持所有jQuery的查詢語(yǔ)法
比如$('a:first')會(huì)報(bào)錯(cuò),只能寫成$('a').first()

具體的使用方法可以通過(guò)cheerio模塊的主頁(yè)來(lái)獲取詳細(xì)的使用說(shuō)明
https://npmjs.org/package/cheerio

3.async模塊
async是一個(gè)使用比較廣泛的JS異步流程控制模塊,除了可以在Nodejs上運(yùn)行,也可以在瀏覽器端運(yùn)行,主要用于處理Nodejs過(guò)程中各種復(fù)雜的回調(diào)
在這里我們主要用到了async的eachSeries方法,他主要用來(lái)異步操作里的串行操作,當(dāng)我們希望在異步流程里上一個(gè)操作執(zhí)行完之后再執(zhí)行下一個(gè),而不是同時(shí)執(zhí)行的時(shí)候,我們就可以通過(guò)eachSeries來(lái)循環(huán)執(zhí)行所有的異步操作。
具體的使用方法可以通過(guò)async模塊的主頁(yè)來(lái)獲取詳細(xì)的使用說(shuō)明
https://npmjs.org/package/async

4.mysql模塊
mysql是Nodejs下比較有名的一個(gè)MySQL操作模塊,我們需要用到這個(gè)模塊來(lái)把我們抓取到的數(shù)據(jù)集存儲(chǔ)到mysql數(shù)據(jù)庫(kù)中
具體的使用方法可以通過(guò)mysql模塊的主頁(yè)來(lái)獲取詳細(xì)的使用說(shuō)明
https://github.com/felixge/node-mysql

最后分享一個(gè)我項(xiàng)目中的一個(gè)完整的網(wǎng)絡(luò)爬蟲(chóng)源碼

var request = require('request');
var cheerio = require('cheerio');
var async = require('async');
var mysql = require('../models/db');

exports.get = function() {
    var domino = 'http://www.tapotiexie.com';
    var url = 'http://www.tapotiexie.com/Line/index/name/yt/p/';
    var txtSource = '踏破鐵鞋';
    var url_list = [];
    var list = [];
    for (var i = 1; i < 25; i++) {
        url_list.push(url + i + '.html');
    }
    async.eachSeries(url_list, function(arr_url, callback) {
        console.log('正在抓取' + arr_url + '的數(shù)據(jù)...');
        request(arr_url, function(err, data) {
            if (err) return console.error(err);
            var $ = cheerio.load(data.body.toString());
            $('.tptx_ytgt .tptx_ytgt_4').each(function() {
                var $me = $(this);
                //解析船公司和船字段
                var arr1 = analyStr($me.find('.tptx_ytgt_2b a').text());
                //解析晚和天
                var arr2 = analyDay($me.find('.tptx_jcyj_2ab_1 span').text());
                var item = {
                    txtCompany: arr1[0],
                    txtCruise: arr1[1],
                    txtLine: analyLine($me.find('.tptx_jcyj_2ab_1 ul li:first-child').text()),
                    txtStartDate: analyStart($me.find('.tptx_jcyj_2ab_1 li').eq(1).text(), $me.find('.tptx_jcyj_2ab_1 span').text()),
                    numDay: Number(arr2[1]),
                    numNight: Number(arr2[0]),
                    numPrice: analyPrice($me.find('.tptx_jcyj_2ac .tptx_jcyj_2ac_1').text()),
                    txtUrl: domino + $me.find('.tptx_ytgt_2b a').attr('href')
                };
                list.push(item);
            });
            callback(err, list);
        });
    }, function(err) {
        if (err) return console.error(err.stack);
        /*寫入數(shù)據(jù)庫(kù)*/
        async.eachSeries(list, function(record, callback) {
            console.log('正在寫入' + record.txtStartDate + '的數(shù)據(jù)...');
            var sql = 'insert into ...';
            mysql.query(sql, function(err, info) {
                if (err) return console.error(err.stack);
                if (info.affectedRows == 1) {
                    callback(err);
                }
            });
        }, function(err) {
            if (err) return console.error(err.stack);
            console.log('處理成功!');
        });
    });
}

/*按中間的空格解析字符串*/
function analyStr(str) {
    var _newStr = '';
    for (i in str) {
        if (str[i].trim() == '') {
            _newStr += '|';
        } else {
            _newStr += str[i];
        }
    }
    return _newStr.split('||');
}

/*解析航線*/
function analyLine(str) {
    var arr1 = str.split("郵輪線路:");
    return arr1[1];
}

/*解析價(jià)格*/
function analyPrice(str) {
    if (str == '售罄') {
        return 0;
    } else {
        var arr1 = str.split("¥");
        var arr2 = arr1[1].split("起");
        return Number(arr2[0]);
    }
}

/*解析晚和天*/
function analyDay(str) {
    var arr1 = str.split('晚');
    var arr2 = arr1[1].split('天');
    var _newStr = arr1[0] + '|' + arr2[0];
    return _newStr.split('|');
}

/*解析出發(fā)日期*/
function analyStart(str1, str2) {
    var arr1 = str1.split(str2);
    var arr2 = arr1[0].split('出發(fā)時(shí)間:');
    return arr2[1];
}

一般的網(wǎng)頁(yè)文章列表都會(huì)采用翻頁(yè)來(lái)實(shí)現(xiàn),那么怎么樣獲取所有的每一頁(yè)的數(shù)據(jù)呢
一般可以通過(guò)抓取“下一頁(yè)”按鈕來(lái)判斷是不是有下一頁(yè)數(shù)據(jù),如果有的話,直接讀取下一頁(yè)鏈接的href屬性

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 目錄Nodejs的介紹15個(gè)Nodejs應(yīng)用場(chǎng)景Nodejs學(xué)習(xí)路線圖 Nodejs的介紹Node.js的是建立在...
    寒劍飄零閱讀 10,512評(píng)論 3 205
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,680評(píng)論 19 139
  • 2017.3.6 - 3.17 學(xué)習(xí)內(nèi)容: 學(xué)習(xí)nodejs數(shù)據(jù)挖掘基本想法 熟悉superagent模塊的基本接...
    ccminn閱讀 1,219評(píng)論 0 3
  • 我傍晚很累, 還拖著殘缺的腿。 人家討厭我,還說(shuō)我美: 我竟無(wú)以答對(duì)! 天寒地凍,無(wú)家可歸。 我整日里奔波游走,我...
    鴦花舞閱讀 202評(píng)論 0 1
  • 迷迷萌萌閱讀 169評(píng)論 8 3

友情鏈接更多精彩內(nèi)容