请选择 进入手机版 | 继续访问电脑版
查看: 190|回复: 4

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

[复制链接]

699

主题

740

帖子

6202

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
6202
发表于 2018-8-9 14:44:10 | 显示全部楼层 |阅读模式
1.主要用的的环境和工具包
开发环境:WEBstorm+win7+Node.js
需要用到的工具包:request和cheerio这两个工具包(使用npm install的方式安装即可)


2.主要源码如下:
[JavaScript] 纯文本查看 复制代码
"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} 保存成功!`);
            });
        })
    });
})


[/size][size=4]

实现思路剖析:
1.可以通过新浪博客的内容看到这个上面抓取的网址,一页基本上有20篇文章左右,关键就用到了那个cheerio工具包,当然你也可以使用原生的JavaScript和正则表达式进行操作
2.实现原理:首先使用request获取请求的url,得到网址的源码,然后使用cheerio将源码解析成为一个JQuery对象,然后使用JQuery直接操作DOM元素解析文章内容
3.关键点:有于当前测试的是一页的博客抓取,对于多页的博客,使用递归的方式进行抓取,主要是通过判断当前博客是不是有下一页的链接,有的话就进行递归,没有的话就停止(递归条件)
4.其他:其他涉及到的就是一些node.js文件的基本读写操作,熟悉的朋友应该都看的懂







上一篇:使用Xamapp快速搭建一个自己的PHP开发运行环境
下一篇:【通知公告】关于我爱科技论坛新增我爱科技在线音乐播放器模块的通知
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案; 如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】。
回复过本主题
的还回复过:

699

主题

740

帖子

6202

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
6202
 楼主| 发表于 2018-8-22 12:53:08 | 显示全部楼层
类似于Python的爬虫,不过这里使用的是JQuery解析的
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案; 如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】。
回复

使用道具 举报

1

主题

5

帖子

13

积分

等待验证会员

积分
13
发表于 2018-9-16 18:55:26 | 显示全部楼层
实现思路不错
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案; 如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】。
回复

使用道具 举报

0

主题

18

帖子

40

积分

新手上路

Rank: 1

积分
40
发表于 2018-11-25 18:47:54 | 显示全部楼层
还不错
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案; 如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】。
回复

使用道具 举报

1

主题

4

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2019-1-16 12:38:39 | 显示全部楼层
很棒的方法 学习了
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案; 如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子分类或者标题加上【已解决】。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

微信扫一扫

我爱科技论坛(www.52tech.tech)旨在打造全网最大的免费资源共享平台。目前论坛包括考研资料、编程学习、黑科技/科学上网、开源软件等资源模块,竭力服务于正在学习道路上的每一个人。我爱科技论坛,爱科技,更爱分享。致力于营造一个资源丰富、内容完善的大型网络学习交流资源共享平台!

QQ|Archiver|手机版|小黑屋|我爱科技论坛 快乐学习交流

(请勿发布违反中华人民共和国法律法规的言论,会员观点不代表我爱科技论坛的官方立场)

Powered by Discuz! X3.4© 2001-2013 Technology Inc.

返回顶部 返回列表