在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('============================= 输出结束 ============================='); }); });
能够来运行下,看看是否正常抓取了数据。
如今有数据数据,能够保存到数据库。这里以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('插入失败'); } }); }); });
运行下,看看数据是否保存到数据库了。
如今一个基本的抓取、保存都有了。可是呢 只抓取一次,并且只能抓取关键词为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);
运行一下,开始抓数据了... 博客园搜索结果100个分页,每页20条数据,供2000条,程序间隔2秒抓取下一页,抓取一个搜索关键词2000条数据约3分20秒左右。
到此程序实现了抓取、保存数据。
若是是其余URL,须要从新解析页面内容,页面编码不是utf-8编码,须要转码,能够借助 iconv-lite 模块。
数据库有了数据,固然能够读取出来,好比按浏览次数多少排序输出来。
按需求,抓取数据,显示数据,助技术进步。