nodejs开发一个爬虫应用

使用cheerio模块来爬取网页上的内容

首先,确保你已经安装了node,如果没有,可以参考node开发环境搭建

初始化项目

新建一个文件夹,目录名随便起一个,在根目录下执行

//初始化package.json文件
npm init
//引入cheerio模块
npm install cheerio --save
//引入定时任务模块
npm install node-schedule --save
//引入axios
npm install axios --save
cheerio 模块介绍

cheerio 是一个 jQuery Core 的子集,其实现了 jQuery Core 中浏览器无关的 DOM 操作 API,去掉了jQuery的一些效果类和请求类等等功能后,仅保留核心对dom操作的部分,因此能够对dom进行和jQuery一样方便的操作 具体操作可以查看cheerio中文文档

node-schedule 模块介绍

node-schedule 是一个在node中实现定时任务的模块,使用他可以很方便的实现定时任务,具体使用方法可以参考文档

http请求方法封装

这里,我们使用axios进行网页内容爬取,先对axios进行封装,可以伪装成浏览器访问、添加cookie等操作,新建api.js文件

const axios = require('axios');

const server = axios.create({
    timeout:10000,
    headers:{//模拟浏览器访问
        'user-agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.75 Safari/537.36'
    }
});

module.exports = {
    get(url){
        return server.get(url);
    },
    post(url,data){
        return server.post(url,data);
    }
}
接下来我们开始爬虫部分代码实现

原理是,先通过axios==发送get请求,获取到目标网站返回的html代码,再通过==cheerio获取到你想要得到的数据等信息 这里,我们已文章网站为例,爬取文章列表、以及文章内容 先审查元素,查看目标网站上你想要获取内容部分的dom结构、class类名、id等信息 这里我们以文章网站为例 QQ截图20210206222414.png

我们需要文章标题、图片列表、文章分类、作者、文章详情跳转链接等信息,通过审查源代码,我们找到文章列表下的dom 找到这些信息对应的class类名、id名称,然后通过cheerio获取出这些信息,组合成你需要的信息 例如

const $http = require('./api.js');
const schedule = require('node-schedule');
const cheerio = require('cheerio');

let list = [];
//这里定义了目标网站的一些文章分类列表的链接
let baseList = [
    "https://cpu.baidu.com",
    "https://cpu.baidu.com/?chn=1022&from=list",
    "https://cpu.baidu.com/?chn=1021&from=list",
    "https://cpu.baidu.com/?chn=1001&from=list",
    "https://cpu.baidu.com/?chn=1013&from=list",
    "https://cpu.baidu.com/?chn=1048&from=list",
    "https://cpu.baidu.com/?chn=1006&from=list",
    "https://cpu.baidu.com/?chn=1002&from=list",
    "https://cpu.baidu.com/?chn=1007&from=list"

];
//随机获取列表
function getList(){
    return new Promise((resolve,reject)=>{
        let index = Math.floor((Math.random()*baseList.length));
        let url = baseList[index];
        $http.get(`${url}`).then((res)=>{
            if(res.status == 200){
                let data = res.data;
                let $ = cheerio.load(data);
                let ls = [];
                $("#main-content .news-list .news-item").each(function(i,e){
                    let item = {};
                    item.title = $(e).find(".n-title span").text();
                    let imglist = [];
                    $(e).find('.n-img-wrapper .img').each(function(j,v){
                        let img_item = $(v).find('img').attr('data-src');
                        if(img_item.indexOf('http') < 0){
                            img_item = 'https:' + img_item;
                        }
                        if(imglist.length < 3){
                            imglist.push(img_item);
                        }
                    });
                    //判断图片数量
                    if(imglist.length >=3){
                        item.extra = imglist;
                    }

                    //获取来源
                    let source_name = $(e).find(".n-desc .info span").eq(1).text();
                    item.source_name  = source_name;
                    //详情链接
                    let url = $(e).find('.n-item-link').attr('href');
                    //判断分类
                    let cat_info = $(e).find('.n-desc .info .cat-info').text();
                    item.cat_info = cat_info;
                    //自定义分类id
                    if(cat_info == "娱乐"){
                        item.catid = "20006";
                    }else if(cat_info == "科技"){
                        item.catid = "20014";
                    }else if(cat_info == "财经"){
                        item.catid = "20013";
                    }else if(cat_info == "体育"){
                        item.catid = "20076";
                    }else if(cat_info == "汽车"){
                        item.catid = "20016";
                    }else if(cat_info == "社会"){
                        item.catid = "1048";
                    }else if(cat_info == "游戏"){
                        item.catid = "1040";
                    }else if(cat_info == "时尚"){
                        item.catid = "20090";
                    }else if(cat_info == "三农"){
                        item.catid = "20091";
                    }else if(cat_info == "手机"){
                        item.catid = "20092";
                    }else if(cat_info == "房产"){
                        item.catid = "20093";
                    }else if(cat_info == "鸡汤美文"){
                        item.catid = "20094";
                    }else if(cat_info == "相声小品"){
                        item.catid = "20095";
                    }else if(cat_info == "美食"){
                        item.catid = "20096";
                    }else if(cat_info == "星座"){
                        item.catid = "20097";
                    }

                    item.url = url;
                    ls.push(item);
                })
                resolve(ls);
            }else{
                console.log("请求失败");
                reject('222');
            }
        })
    })
}
//获取文章详情
function getContent(url){
    return new Promise((resolve,reject)=>{
        $http.get(`https://cpu.baidu.com${url}`).then((res)=>{
            if(res.status == 200){
                resolve(res.data);
            }
        })
    })
}
async function init(){
    if(list.length == 0){
        list = await getList();
    }
    let data = list.pop();
    if(data.title.length > 40){
        console.log('文章标题过长,不采集');
        return;
    }
    if(data.title && data.extra){
        let html = await getContent(data.url);
        let $ = cheerio.load(html,{decodeEntities:false});
        let thumb = data.extra[0] || "";
        data.extra = JSON.stringify(data.extra);
        $("#main-content .article").find('img').each(function(i,e){
            let url = $(this).attr("data-src");
            $(this).attr("src",url);
        });
        $("#main-content .article").find(".content").each(function(i,e){
            $(this).attr("style","");
        })
        let content = $("#main-content .article").html();
        let postdata = {
            catid:data.catid,
            title:data.title,
            source_name:data.source_name,
            thumb:thumb,
            extra:data.extra || '',
            content:content,
        };
        //postdata为最终采集数据,保存流程需自行实现
        console.log(postdata);
    }else{
        console.log("无此分类"+data.cat_info);
    }
}

//定时执行采集任务
let rule = new schedule.RecurrenceRule();

let times = [0,15,30,45];

rule.second = times;

schedule.scheduleJob(rule,()=>{
    init();
})

至此,一个简单的爬虫应用就完成了,代码很简单,只是给大家提供一个思路,可以参考示例项目