Node爬取大批量文件的方法示例


Posted in Javascript onJune 28, 2019

有个朋友在搞留学工作室,经常访问的一个网站叫留学者指南,然而每次都要去访问该网站,显得极其不专业。于是托俺帮忙写脚本去爬他家的东西,我观察了下,这次,我们要爬的东西就有点多了——大概就20多万个文件吧~~~

在20多万个文件中,下载极有可能会被中断,因此需要做下载进度备份,下载进度恢复。

那么针对这样子的需求,我们开始吧!

上代码!

const cheerio = require("cheerio"); //用于处于HTML文档流,用法类似jQuery
const http = require("http"); //用于发起请求
const fs = require("fs"); //用于检测、写入文件等其他文件操作

// "http://www.compassedu.hk/sitemap1.txt",
// "http://www.compassedu.hk/sitemap2.txt", //重复的链接
var source = [ //Robots.txt显示的数据源
  "http://m.compassedu.hk/sitemap3.txt",
  "http://m.compassedu.hk/sitemap4.txt",
  "http://m.compassedu.hk/sitemap6.txt",
  "http://m.compassedu.hk/sitemap7.txt",
  "http://m.compassedu.hk/sitemap8.txt"
]
var s = 0; //控制源的序号
var arr = []; //合并的下载地址数组
var sou = []; //源下载地址数组
var i = 0; //当前下载地址数组序号

fs.exists(__dirname+"/compassedu", function(flag){ //下载路径检测
  if(!flag) fs.mkdirSync(__dirname+"/compassedu"); //创建下载存放目录
})
fs.exists(__dirname+"/logs", function(flag){ //日志路径检测
  if(!flag) fs.mkdirSync(__dirname+"/logs"); //创建日志存放目录
})

if(fs.existsSync(__dirname+"/logs/compassedu_backup")){ //是否存在断连恢复下载的控制文档
  let obj = JSON.parse(fs.readFileSync(__dirname+"/logs/compassedu_backup")); //存在则读取上次下载的位置
  i = obj.index;
  init(); //开始初始化程序
}
else{
  init(); //开始初始化程序
}

function init(){ //初始化
  http.get(source[s], function(res){ //获取源下载地址文件

    //将源文件的内容存储到数组
    let rawData = "";
    res.setEncoding("utf8");
    res.on("data", function(chunk){ //监听数据流
      rawData += chunk;
    });
    res.on("end", function(){ //监听结束
      sou[s] = rawData.split("\n");
      console.log("源", s+1, ": ", sou[s].length, "条数据");
      s++;
      if(s<source.length){ //源文件还未读取完
        init();
      }
      else{ //源文件读取完毕
        for(let m=0;m<sou.length;m++){ //将所有的地址数组合并
          arr = arr.concat(sou[m]);
        }
        arr = [...new Set(arr)]; //去重
        console.log("总计: ", arr.length, "条数据", "\n爬虫配置完毕!!\n开始爬取 >>");
        start(); //开始爬取程序
      }
    });
  })
}

function start(){ //开始
  let url = arr[i];
  console.log(url); //打印当前爬取的URL
  
  http.get(url,function(res){ //发起请求
    let obj = { //将当前的信息存储到对象中
     "time": new Date().toLocaleTimeString(),
      "index": i,
      "url": url,
      "status": res.statusCode
    };
    fs.appendFileSync("./logs/download.log", JSON.stringify(obj), "utf8"); //写入日志文件
    fs.writeFileSync("./logs/compassedu_backup", JSON.stringify({"index": i}), "utf8"); //将当前的下载URL序号写入断连恢复文件
    //读取请求到的数据流
    let rawData = "";
    res.setEncoding("utf8");
    res.on("data", function(chunk){ //监听数据流事件
      rawData += chunk;
    });
    res.on("end", function(){ //监听结束事件
      $ = cheerio.load(rawData); //启用类jQuery插件
      title = $(".container-public h1").text().replace(/\s/,"").trim(); //读取数据流部分的标题
      body = $(".container-public").html(); //读取数据流部分的内容
      body = body.split("visible-xs")[0]; //剥离多于的数据或其他处理,准备写入文件
      i++; //序号+1
      fs.writeFile(__dirname+"/compassedu/"+title+".html", body, "utf8", function(err){ //将处理好的数据写入文件
        if(!err) console.log(title, "写入成功");
        else{
          console.log(err);
        }
      });
      if(i>=arr.length) { //若序号达到数组的最后,结束程序
        console.log("爬取结束");
        fs.unlinkSync("./logs/compassedu_backup");//爬取结束,销毁断连恢复文件
        return;
      }
      else { //否则递归运行
        start();
      }
    });
    res.on("error", function(err){ //监听其他错误
      console.log(err);
    });
  })
}

至此,就结束了,是否有bug还不清楚,数据还没爬完呢~

有bug的话,我后续补充修复~

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
fromCharCode和charCodeAt 方法
Dec 27 Javascript
js 对象是否存在判断
Jul 15 Javascript
菜鸟javascript基础整理1
Dec 06 Javascript
javascript之典型高阶函数应用介绍二
Jan 10 Javascript
HTML5使用DeviceOrientation实现摇一摇功能
Jun 05 Javascript
Javascript控制div属性动态变化实例分析
Oct 08 Javascript
IE6-IE9使用JSON、table.innerHTML所引发的问题
Dec 22 Javascript
Bootstrap选项卡与Masonry插件的完美结合
Jul 06 Javascript
使用cropper.js裁剪头像的实例代码
Sep 29 Javascript
node中modules.exports与exports导出的区别
Jun 08 Javascript
有关vue 开发钉钉 H5 微应用 dd.ready() 不执行问题及快速解决方案
May 09 Javascript
jQuery实现鼠标滑动切换图片
May 27 jQuery
JavaScript实现单英文金山打字通
Jul 24 #Javascript
javascript实现导航栏分页效果
Jun 27 #Javascript
编写更好的JavaScript条件式和匹配条件的技巧(小结)
Jun 27 #Javascript
原生js实现抽奖小游戏
Jun 27 #Javascript
JavaScript实现图片放大镜效果
Jun 27 #Javascript
详解Jest结合Vue-test-utils使用的初步实践
Jun 27 #Javascript
微信小程序自定义组件实现环形进度条
Nov 17 #Javascript
You might like
火车采集器 免费版使出收费版本功能实现原理
2009/09/17 PHP
php foreach、while性能比较
2009/10/15 PHP
PHP中使用localhost连接Mysql不成功的解决方法
2014/08/20 PHP
php实现的简单日志写入函数
2015/03/31 PHP
重写javascript中window.confirm的行为
2012/10/21 Javascript
js实现DOM走马灯特效的方法
2015/01/21 Javascript
原生JS实现LOADING效果
2015/03/16 Javascript
Javascript中Array用法实例分析
2015/06/13 Javascript
jquery中toggle函数交替使用问题
2015/06/22 Javascript
javascript给span标签赋值的方法
2015/11/26 Javascript
jQuery实现的鼠标滑过弹出放大图片特效
2016/01/08 Javascript
图解prototype、proto和constructor的三角关系
2016/07/31 Javascript
Vue.js每天必学之组件与组件间的通信
2016/09/08 Javascript
利用浮层使select不可选的实现方法
2016/12/03 Javascript
JS/jquery实现一个网页内同时调用多个倒计时的方法
2017/04/27 jQuery
jQuery中的$是什么意思及 $. 和 $().的区别
2018/04/20 jQuery
Easyui 关闭jquery-easui tab标签页前触发事件的解决方法
2019/04/28 jQuery
微信小程序登录数据解密及状态维持实例详解
2019/05/06 Javascript
小程序实现搜索框
2020/06/19 Javascript
微信小程序动画组件使用解析,类似vue,且更强大
2019/08/01 Javascript
Vue监听滚动实现锚点定位(双向)示例
2019/11/13 Javascript
JavaScript 如何计算文本的行数的实现
2020/09/14 Javascript
Python enumerate遍历数组示例应用
2008/09/06 Python
python3对接mysql数据库实例详解
2019/04/30 Python
使用python实现简单五子棋游戏
2019/06/18 Python
解决Python3 抓取微信账单信息问题
2019/07/19 Python
对Django中的权限和分组管理实例讲解
2019/08/16 Python
关于Pytorch MaxUnpool2d中size操作方式
2020/01/03 Python
Pytorch中的VGG实现修改最后一层FC
2020/01/15 Python
Python图像处理库PIL的ImageGrab模块介绍详解
2020/02/26 Python
经管应届生求职信
2013/11/17 职场文书
健康教育评估方案
2014/05/25 职场文书
多媒体教室标语
2014/06/26 职场文书
国王的演讲观后感
2015/06/03 职场文书
小程序教您怎样你零成本推广获取数万用户的方法
2019/07/30 职场文书
详解如何用Python实现感知器算法
2021/06/18 Python