NodeJs爬虫-Crawler与Async结合爬取小说网站

05-23
评论
字数统计:2905(字)
demo展示node-crawler与async结合串行执行,实现爬取小说网站。

前言

  • 此demo展示node-crawler与async结合串行执行,爬取小说网站,并将每个章节内容存入本地。
  • 实例中爬取的某小说网站,只为学习不做商业行为,如有侵权请联系我。
  • 源码至 github,包含ts版。

安装

npm install async crawler
# or
yarn add async crawler

demo

nodejs开发最大的烦恼就是异步问题,async就是解决这个问题而存在的,这里不做过多的介绍。 先上代码:

const Crawler = require("crawler");
const async = require("async");
const fs = require("fs");
const path = require("path");

const url = `http://www.52ggd.com/book/5/5203`;

(async function () {
  /** 使用async列队,分为两个实例爬取 */
  /** waterfall函数可将上次的执行结果传递到下一次 */
  console.time("执行时间");
  console.log("爬虫开始");
  async.waterfall([getAllChapter, getContent], (error, res) => {
    if (error) {
      console.error(error);
    } else {
      console.log("爬虫结束");
    }
    console.timeEnd("执行时间");
  });
})();

/** 获取小说所有章节 */
function getAllChapter(cb) {
  var chapterList = [];
  const crawler = new Crawler({
    callback: function (error, res, done) {
      if (error) {
        console.error(error);
      }
      const $ = res.$;

      const container = $(".chapterlist");
      const lis = $(container[0]).children("dd");

      lis.map((index, i) => {
        chapterList.push({
          /** 这里路由拼进去一个/ */
          link: `${url}/${$(i).children("a").attr("href")}`,
          name: $(i).children("a").text(),
        });
      });

      done();
    },
  });

  /** 选取小说的目录页 */
  crawler.queue(url);

  /** 队列结束调用 */
  crawler.on("drain", async () => {
    console.log(`所有章节已导出 共${chapterList.length}`);
    /** async 回调,第一个参数为错误信息,没有错误就null */
    /** chapterList 最终会传递到下一个队列 */
    cb(null, chapterList);
  });
}

/** 获取小说内容 */
function getContent(chapter, cb) {
  const crawler = new Crawler({
    maxConnections: 200 /** 队列执行的个数,设置大些,防止章节过多丢失 */,
    // rateLimit: 1,
    callback: async function (error, res, done) {
      if (error) {
        console.error(error);
      }
      const $ = res.$;

      const contentBox = $("#BookText");
      const content = $(contentBox[0]).text();

      console.log(`开始爬取【${res.options.filename}`);

      const localPath = path.resolve(__dirname, `txt`);
      !fs.existsSync(localPath) && fs.mkdirSync(localPath);
      await fs
        .createWriteStream(
          path.resolve(localPath, `${res.options.filename}.txt`)
        )
        .write(content);

      done();
    },
  });

  /** queue队列并行执行 */
  crawler.queue(
    chapter.map(function (m) {
      return { uri: m.link, filename: m.name };
    })
  );

  crawler.on("drain", async function () {
    console.log(`所有内容写入完毕,存入:${path.resolve(__dirname, `txt`)}`);
    cb(null);
  });
}
本文链接:https://blog.crazylei.com/art/44aa8778
版权声明: 本博客所有文章除特别声明外,均采用CC BY 4.0 CN协议 许可协议。转载请注明出处!

评论

正在加载评论...

©2022 Crazylei Bolg沪ICP备20001821号