• node.js抓取数据(fake小爬虫)


      在node.js中,有了 cheerio 模块、request 模块,抓取特定URL页面的数据已经非常方便。

      一个简单的就如下

    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.js 

      

      得到如下的URL:

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

      点击第二页,URL如下:

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

      分析URL,发现w= ?为要搜索的关键词 p= ?为页码。 

      借助 request 模块请求URL 

    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 模块。 

       数据库有了数据,当然可以读取出来,比如按浏览次数多少排序输出来。

       按需求,抓取数据,显示数据,助技术进步。

        

  • 相关阅读:
    python之bytes和string(转)
    http post请求传文件报错 invalid character '' in numeric literal
    正则表达式匹配从指定字符开始到指定字符结束的字符串
    为什么提倡会议上要多提问?
    4K 显示器突然变模糊了怎么调回来
    快速将 gif 图转成 jpg 图片
    <一>window安装git
    <二>使用git将本地项目上传到gitee
    <一>window安装rabbitmq
    <一>redis安装
  • 原文地址:https://www.cnblogs.com/eyeear/p/4760189.html
Copyright © 2020-2023  润新知