记录自己的爬虫经验
本次是爬取某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" }
原文地址:https://www.cnblogs.com/dukeshao/p/10891675.html
时间: 2024-08-28 20:39:25