跳到正文

【JavaScript爬虫】使用JavaScript+Nodejs抓取新浪博客内容的思路和源码分析

1.主要用的的环境和工具包 开发环境:Webstorm+win7+Node.js 需要用到的工具包:request和cheerio这两个工具包(使用npm install的方式安装即可) 2.主要源码如下: "use strict"; const request = require('request'); const cheerio = require('cheerio'); const fs = require('fs'); const path = require('path'); const url = 'http://blog.sina.com.cn/s/articlelist_1196037175_0_1.html'; // 获取模板字符串, 慧姐使用同步的方式读取数据 // 在外部拿到模板字符串,为了多次使用 const templateStr = fs.readFileSync(path.join(__dirname, 'template.html')); /** * 用户获取文章的列表信息 * @param url * @param callback */ function getArticleList(url, callback) { request(url, function (err, res, body) { if (err) { //throw new Error('error'); return callback(err, null); //return; } // 开始解析body let $ = cheerio.load(body); // 定义一个数组,用于存储解析的结果信息 let articleList = ; //console.log($.html()); // 注意: 在使用箭头函数的时候, 函数内部的this并不是绑定的每一项 $('.articleList .articleCell ').each(function () { // 拿到每一行的元素, 这里如果使用箭头函数的时候访问this的话,就会找不到了 let $this = $(this); //console.log(this); error //console.log($this); // 得到文章标题链接 let $title = $this.find('.atc_title a'); // 得到时间(注意事项:一个class标签可能是会有多个class的属性) let $time = $this.find('.atc_tm'); articleList.push({ title: $title.text(), url: $title.attr('href'), time: $time.text() }); }); // 实现递归抓取文件的思路 // 1. 递归条件: 是否有下一页 // 当前页面内容抓取完毕之后,开始抓取下一页的内容 let nextURL = $('.SG_pgnext a').attr('href'); if (nextURL){ // 如果有下一下的话,就进行递归抓取 getArticleList(nextURL, function (err, list) { if (err){ return callback(err, null); } // 如果有下一次的话,就把本次的数据集合和上一次结果集合放在一起 callback(null, articleList.concat(list)); }); } else{ // 打印输出得到的文件列表 //console.log(articleList); callback(null, articleList); } }); } /** * 获取文章的细节信息 * @param url * @param callback */ function getDetailByUrl(url, callback) { // 进入到文章的细节信息 request(url, function (err, res, body) { if (err) { return callback(err, null); } // 把body转换为一个类似于JQuery的对象 let $ = cheerio.load(body, { decodeEntities: false // 把内容的编码设置一下 }); // 获取博客的内容信息 let html = $('.articalContent').html(); let content = (html === null ? html : html.toString().trim()); callback(null, content); }) } // 获取所有的文章列表信息 /** * 这是一个函数调用,用于获取文章列表之后所执行的一系列操作 */ getArticleList(url, function (err, articleList) { if (err) { throw new Error('error'); } //console.log(articleList); articleList.forEach(function (item, index) { let url = item.url; // 根据博客的URL信息偶去博客的内容信息 // 获取信息这实际上是一个异步信息,会直接把这么多的信息加入到事件队列中区 getDetailByUrl(url, function (err, detail) { if (err) { return console.log(err, url); } // 获取到数据之后保存信息到本地 // 【注意事项: 在Nodejs中向一个文件中写入数据的时候必须保证这个文件夹路径存在,否则会报错!】 let filePath = path.join(__dirname, 'data', item.title.toString().trim() + '.html'); // 使用 replace的方式来设置模板中的内容信息 detail = templateStr.toString().replace('<%content%>' , detail); fs.writeFile(filePath, detail, (err) => { if (err) { return console.log(filePath + '文件保存失败!') } console.log(`文件: ${filePath} 保存成功!`); }); }) }); }) 实现思路剖析: 1.可以通过新浪博客的内容看到这个上面抓取的网址,一页基本上有20篇文章左右,关键就用到了那个cheerio工具包,当然你也可以使用原生的JavaScript和正则表达式进行操作 2.实现原理:首先使用request获取请求的url,得到网址的源码,然后使用cheerio将源码解析成为一个JQuery对象,然后使用JQuery直接操作DOM元素解析文章内容 3.关键点:有于当前测试的是一页的博客抓取,对于多页的博客,使用递归的方式进行抓取,主要是通过判断当前博客是不是有下一页的链接,有的话就进行递归,没有的话就停止(递归条件) 4.其他:其他涉及到的就是一些node.js文件的基本读写操作,熟悉的朋友应该都看的懂

评论

填写昵称与邮箱即可评论,无需登录。

推荐阅读