美文网首页
nodeJS(request+cheerio+pump)稳定爬取

nodeJS(request+cheerio+pump)稳定爬取

作者: 被代码耽误的裁缝 | 来源:发表于2019-06-01 16:12 被阅读0次

本次是爬取某SSR网站列表页及详情页数据,包括文本及图片,将数据存入MongoDB数据库,将图片下载至本地;

首先呢,用到的nodeJS模块有:

  • request: 用于请求网址内容或请求图片内容
  • cheerio: 通俗的讲,可以当做jQuery使用
  • pump: 一种管道,操纵数据流,比原生的pipe好用,可操控性强,具体用法可去npm查询
  • path: 读取操作文件路径
  • fs: 操作文档读写等
第一步:引入需要用到的相关模块,建议用yarn安装以下模块
const request = require("request");
const cheerio = require("cheerio");
const path = require("path");
const fs = require("fs");
const pump = require("pump");
var Bagpipe = require('bagpipe');
第二步:连接Mongodb
//集合名称
const colName = 'xiaorizi';
//1.引入模块中的客户端对象
const { MongoClient } = require('mongodb');
const { mongo: mongourl, database } = require('../config.json');

var client, db, collection
//2.利用MongoClient连接数据
(async function connect() {
    client = await MongoClient.connect(mongourl, { useNewUrlParser: true });
    //连接数据库,无则自动创建
    db = await client.db(database);
    //根据colName获取集合
    collection = await db.collection(colName);
})()

// @增 定义写入数据库函数
async function create(data) {
    //执行mongo增加数据语句
    let result;
    try {
        result = await collection[Array.isArray(data) ? 'insertMany' : 'insertOne'](data);
    } catch (err) {
        result = err;
    }
}
第三步:配置需要用到的全局变量
//配置网址
let base = "7595"
//配置列表页数
let len = 2;
//配置店铺类型
let lu = "film";


//配置图片名称类型
let lujin = "./" + lu + "/" + lu + "_";
//配置请求基本网址
let baseurl = "http://m.xiaorizi.me/t" + base;

//生成列表页网址数组
let arr = [];
for (var j = 0; j < len; j++) {
    arr[j] = baseurl + "_p" + (j + 1) + "/";
}
console.log(arr);


//所有页店铺数量
let list_num = 0;

//所有详情页图片数量
let list_imgNum = 1;
第四步:开启进程
//开启10个进程爬取详情页图片
var bagpipe = new Bagpipe(10);
//开启4个进程爬取列表页图片
var bagpipe1 = new Bagpipe(4);
//记录爬取成功的详情页图片数量
var index = 1;

//定义下载图片函数
function downloadImage(src, dest, callback) {
  request.head(src, function (err, res, body) {
    // console.log('content-type:', res.headers['content-type']);
    // console.log('content-length:', res.headers['content-length']);
    if (src) {
      var source = request(src);
      pump(source, fs.createWriteStream(dest)).on('close', function () {
        callback(null, dest);
      });
    }
  })
}
第五步:遍历所有页面,爬取列表页及详情页
//遍历所有页
for (var g = 0; g < arr.length; g++) {

    //请求单页
    request(arr[g], async (error, response, body) => {
        //载入网站内容至body
        let $ = cheerio.load(body);
        // 利用jquery的核心方法获取html代码中的具体元素
        await $('.shops>li', 'body').each(async (i, e) => {
            //标题
            let list_title = $(e).find("h3").text();
            //店铺
            let list_store = $(e).find(".tag").text();
            //地址
            let list_address = $(e).find("p").last().text();
            //图片src
            let list_imgSrc = $(e).find("a").first().find("img").attr("data-original");
            if (list_imgSrc) {
                //获取图片后缀名
                let back1 = path.basename(list_imgSrc).match(/[\.].+/);
                //将图片改名
                let list_imgName = lujin + list_imgNum++ + back1;
                //图片名称
                let list_Img = path.basename(list_imgName)
                //爬取列表页图片
                await bagpipe1.push(downloadImage, list_imgSrc, list_imgName, async (err, data) => {
                    //爬取详情页面
                    let detailSrc = "http://m.xiaorizi.me" + $(e).find("a").first().attr("href");
                    await request(detailSrc, async (err, res, bodys) => {
                        let $2 = cheerio.load(bodys);

                        //如果详情页存在
                        if ($2(".title_h")) {
                            list_num++;
                            //标题
                            let detail_title = [];
                            detail_title[0] = $2(".title_h").text();
                            detail_title[1] = $2(".title_p").text();
                            console.log("第" + list_num + "个店铺:", list_store)

                            //店铺详情
                            let detail_shop = [];
                            $2(".shop_detail li").each((i) => {
                                detail_shop[i] = $2($2(".shop_detail li")[i]).text();
                            })

                            //主要内容
                            let detail_cont = [];

                            //详情页图片数量
                            let detail_imgNum = 0;

                            //详情页文本及图片
                            $2(".content").children().each((i, e) => {
                                //如果到达底部结束标签p1则停止爬取
                                if ($2(e).prop("className") == "p1") {
                                    return;
                                }

                                //单个文本对象或图片对象
                                let obj = {};
                                obj.tagName = $2(e).prop("tagName");
                                if (obj.tagName == "P") {
                                    obj.value = $2(e).text();
                                    //如果P标签有内容再推入detail_cont数组
                                    if (obj.value != "") {
                                        detail_cont.push(obj);
                                    }
                                } else if (obj.tagName == "IMG") {
                                    //获取图片地址
                                    let detail_imgSrc = $2(e).attr("src");
                                    //匹配图片后缀名
                                    let back2 = path.basename(detail_imgSrc).match(/[\.].+/);
                                    //定义图片路径及名称
                                    let detail_imgName = lujin + "d_" + list_num + "_" + ++detail_imgNum + back2;
                                    obj.value = path.basename(detail_imgName);
                                    detail_cont.push(obj);

                                    //爬取详情页图片
                                    bagpipe.push(downloadImage, detail_imgSrc, detail_imgName, (err, data) => {
                                        console.log("[" + index++ + "]:" + data);
                                    })
                                }
                            })
                            create({
                                city: list_store.split(" ")[0],
                                type: list_store.split(" ")[1],
                                list_Img,
                                list_title,
                                list_store,
                                list_address,
                                detail_title,
                                detail_shop,
                                detail_cont
                            })
                        } else {
                            console.log("详情页不存在:" + list_store)
                        }
                    })
                })
            }
        })
    })
}

备注:config.json配置如下

{
    "PORT": 19011,
    "mongo": "mongodb://localhost:27017",
    "database": "runoob"
}

相关文章

  • nodeJS(request+cheerio+pump)稳定爬取

    本次是爬取某SSR网站列表页及详情页数据,包括文本及图片,将数据存入MongoDB数据库,将图片下载至本地; 首先...

  • nodejs + cheerio 爬取极客学院的nodejs课程

    文章概要 使用nodejs + cheerio 对极客学院的nodejs课程数据进行爬取。统计nodejs系列课程...

  • NodeJS小说爬虫

    这是一个NodeJS爬虫项目,用于爬取爱去小说网的小说资源,非常适合新手学习NodeJS,感受NodeJS的魅力经...

  • Nodejs爬取cnode精华板块

    学习nodejs已经有段时间,网上很多nodejs爬虫的文章,所以着手练习写一段nodejs爬取鼎鼎大名的node...

  • Nodejs爬取新闻列表

    爬取地址 https://www.thepaper.cn/ 使用到的库 superagent (页面数据下载) c...

  • nodejs爬取网页图片

    一、思路概述 1、通过node内置的http/https模块获取指定网站html2、通过第三方cheerio模块提...

  • 使用NodeJs爬取数据

    使用NodeJs爬取数据 前言 最近因为一个外行朋友让我帮忙整理一个网站的数据,我第一时间就想到了就写爬虫去爬取,...

  • nodejs+axios爬取html出现中文乱码

    当使用 nodejs + axios 来爬取某个 url 对应的 html 时,出现中文乱码。 一、乱码原因 在 ...

  • nodeJS做一个简单的爬虫

    nodeJS(准确的说是express+request+cheerio)做一个简单的爬虫,爬取豆瓣电影的电影图片,...

  • 随处可见的学习笔记-Redis入门

    他山之石,可以攻玉 引言 前两天写了个NodeJs爬虫,很简单那种。就是爬取某个网站的首页解析所有的Url然后再爬...

网友评论

      本文标题:nodeJS(request+cheerio+pump)稳定爬取

      本文链接:https://www.haomeiwen.com/subject/iydatctx.html