node.js抓取數據(fake小爬蟲)

  在node.js中,有了 cheerio 模塊、request 模塊,抓取特定URL頁面的數據已經很是方便。javascript

  一個簡單的就以下java

var request = require('request');
var cheerio = require('cheerio');

request(url,function(err,res){
    if(err) return console.log(err);
    var $ = cheerio.load(res.body.toString());
     
    //解析頁面內容

});

   有了基本的流程,如今找個web地址(url)試試。就以博客園的搜索頁爲例。node

   經過搜索關鍵詞 node.js mysql

  

  獲得以下的URL:web

  http://zzk.cnblogs.com/s?t=b&w=node.jssql

  點擊第二頁,URL以下:mongodb

  http://zzk.cnblogs.com/s?t=b&w=node.js&p=2數據庫

  分析URL,發現w= ?爲要搜索的關鍵詞 p= ?爲頁碼。 瀏覽器

  藉助 request 模塊請求URL ide

var request = require('request');
var cheerio = require('cheerio');

var key = 'node.js', page = 1;
var url = 'http://zzk.cnblogs.com/s?t=b&w='+ key +'&p='+ page;

request(url, function(err, res) {
    if (err) return console.log(err);
    var $ = cheerio.load(res.body.toString());
    var arr = [];
    //內容解析
    
    
});

  如今URL有了,分析下URL對應的頁面內容。

  

  頁面仍是頗有規律的。

  標題 摘要 做者  發佈時間 推薦次數 評論條數 瀏覽次數 文章連接

  藉助瀏覽器開發工具

  

  發現 <div class="searchItem">...</div> 對應的是每篇文章

  點開每一項,有以下內容

  

  class="searchItemTitle" 包含的是文章標題、也包含了文章URL地址

  class="searchItemInfo-userName" 包含的是做者

  class="searchItemInfo-publishDate" 包含的是發佈時間

  class="searchItemInfo-views" 包含的是瀏覽次數

  藉助 cheerio 模塊解析文章,抓取具體的內容

var request = require('request');
var cheerio = require('cheerio');

var key = 'node.js', page = 1;
var url = 'http://zzk.cnblogs.com/s?t=b&w='+ key +'&p='+ page;

request(url, function(err, res) {
    if (err) return console.log(err);
    var $ = cheerio.load(res.body.toString());
    var arr = [];
    //內容解析
    $('.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('============================= 輸出結束 =============================');
    });
});
View Code

  能夠來運行下,看看是否正常抓取了數據。  

   

   如今有數據數據,能夠保存到數據庫。這裏以mysql爲例,其實用mongodb更方便。

   藉助 mysql 模塊保存數據(假設數據庫名爲test,表爲blog)。

   

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: 'test'
});
db.connect();

var key = 'node.js', page = 1;
var url = 'http://zzk.cnblogs.com/s?t=b&w='+ key +'&p='+ page;

request(url, function(err, res) {
    if (err) return console.log(err);
    var $ = cheerio.load(res.body.toString());
    var arr = [];
    //內容解析
    $('.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('插入失敗');
            }
        });
    });
});
View Code

   運行下,看看數據是否保存到數據庫了。

  

    如今一個基本的抓取、保存都有了。可是呢 只抓取一次,並且只能抓取關鍵詞爲node.js 頁碼爲1的URL頁面。

    改關鍵詞爲javascript,頁碼爲1,清空blog表,再重新運行一次,看看錶裏是否是能保存javascript相關的數據。

    

    如今去博客園搜索javascript,看看搜索到的結果和表裏的內容可否對應。呵呵,不用看啦,確定能對應啊~~

    只能抓取一個頁面的內容,確定不能知足的,能自動抓取其餘頁的內容就更好了。

    分析搜索頁面,底部都有頁碼、下一頁。

    

   藉助瀏覽器開發工具查看

 

  咱們發現最後一個a標籤的內容有Next,表示下一頁,看href有p=2,在第二分頁p=3, ... 最後一頁沒有內容有Next的a標籤了。

var nextA = $('.pager a').last(),
    nextUrl = '';
if ($(nextA).text().indexOf('Next') > -1) {
    nextUrl = nextA.attr('href');
    page = nextUrl.slice(nextUrl.indexOf('p=') + 2);

    //todo

} else {
    db.end();
    console.log('沒有數據了...');
}

  這裏把程序代碼作一點修改,封裝成一個函數,完整以下:

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: 'test'
});
db.connect();

function fetchData(key, page) {
    var url = 'http://zzk.cnblogs.com/s?t=b&w=' + key + '&p=' + page;
    request(url, function(err, res) {
        if (err) return console.log(err);
        var $ = cheerio.load(res.body.toString());
        var arr = [];
        //內容解析
        $('.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('p=') + 2);
            setTimeout(function() {
                fetchData(key, page);
            }, 2000);
        } else {
            db.end();
            console.log('沒有數據了...');
        }
        
    });
}
fetchData('node.js', 1);
View Code

   運行一下,開始抓數據了... 博客園搜索結果100個分頁,每頁20條數據,供2000條,程序間隔2秒抓取下一頁,抓取一個搜索關鍵詞2000條數據約3分20秒左右。

   到此程序實現了抓取、保存數據。

   若是是其餘URL,須要從新解析頁面內容,頁面編碼不是utf-8編碼,須要轉碼,能夠藉助 iconv-lite 模塊。 

   數據庫有了數據,固然能夠讀取出來,好比按瀏覽次數多少排序輸出來。

   按需求,抓取數據,顯示數據,助技術進步。

相關文章
相關標籤/搜索