本次是爬取某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"
}
网友评论