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 相关文章推荐
javascript脚本编程解决考试分数统计问题
Oct 18 Javascript
关于javascript中的typeof和instanceof介绍
Dec 04 Javascript
Javascript学习笔记之 对象篇(四) : for in 循环
Jun 24 Javascript
js实现按一下删除键删除整个单词附demo
Sep 05 Javascript
快速解决Canvas.toDataURL 图片跨域的问题
May 10 Javascript
javascript匀速动画和缓冲动画详解
Oct 20 Javascript
浅谈JS函数定义方式的区别
Oct 30 Javascript
Bootstrap警告框(Alert)插件使用方法
Mar 21 Javascript
微信小程序五星评分效果实现代码
Apr 06 Javascript
Angular2使用vscode断点调试ts文件的方法
Dec 13 Javascript
解决JSON.stringify()自动将中文转译成unicode的问题
Jan 05 Javascript
使用jquery-easyui的布局layout写后台管理页面的代码详解
Jun 19 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
php隐藏IP地址后两位显示为星号的方法
2014/11/21 PHP
WordPress开发中用于标题显示的相关函数使用解析
2016/01/07 PHP
php报错502badgateway解决方法
2019/10/11 PHP
JavaScript入门教程(9) Document文档对象
2009/01/31 Javascript
讨论javascript(一)工厂方式 js面象对象的定义方法
2009/12/15 Javascript
js压缩工具 yuicompressor 使用教程
2010/03/31 Javascript
jQuery 顺便学习下CSS选择器 奇偶匹配nth-child(even)
2010/05/24 Javascript
Prototype源码浅析 String部分(三)之HTML字符串处理
2012/01/15 Javascript
jQuery实现HTML5 placeholder效果实例
2014/12/09 Javascript
js闭包引起的事件注册问题介绍
2016/03/29 Javascript
深入理解Angularjs向指令传递数据双向绑定机制
2016/12/31 Javascript
javascript函数的四种调用模式
2017/01/08 Javascript
Angular.js中ng-if、ng-show和ng-hide的区别介绍
2017/01/20 Javascript
javascript 开发之百度地图使用到的js函数整理
2017/05/19 Javascript
JS验证码实现代码
2017/09/14 Javascript
vue异步加载高德地图的实现
2018/06/19 Javascript
jQuery实现二级导航菜单的示例
2020/09/30 jQuery
Python2.6版本中实现字典推导 PEP 274(Dict Comprehensions)
2015/04/28 Python
Python2.x版本中基本的中文编码问题解决
2015/10/12 Python
python处理数据,存进hive表的方法
2018/07/04 Python
python爬取微信公众号文章的方法
2019/02/26 Python
pandas 数据索引与选取的实现方法
2019/06/21 Python
python lambda表达式在sort函数中的使用详解
2019/08/28 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
2019/09/10 Python
Django restframework 框架认证、权限、限流用法示例
2019/12/21 Python
Python参数传递实现过程及原理详解
2020/05/14 Python
matplotlib交互式数据光标mpldatacursor的实现
2021/02/03 Python
6种非常炫酷的CSS3按钮边框动画特效
2016/03/16 HTML / CSS
html5使用canvas绘制太阳系效果
2014/12/15 HTML / CSS
洲际酒店集团大中华区:IHG中国
2016/08/17 全球购物
CSS代码检查工具stylelint的使用方法详解
2021/03/27 HTML / CSS
银行员工辞职信范文
2014/01/20 职场文书
建筑工地标语
2014/06/18 职场文书
2014年群众路线教育实践活动整改措施
2014/09/24 职场文书
小学体育教学随笔
2015/08/14 职场文书
JavaScript的Set数据结构详解
2022/02/18 Javascript