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 相关文章推荐
JCalendar 日历控件 v1.0 beta[兼容IE&amp;Firefox] 有文档和例子
May 30 Javascript
一个简单的js鼠标划过切换效果
Jun 30 Javascript
为Extjs加加速(javascript加速)
Aug 19 Javascript
ASP.NET jQuery 实例3 (在TextBox里面阻止复制、剪切和粘贴事件)
Jan 13 Javascript
jquery动画4.升级版遮罩效果的图片走廊--带自动运行效果
Aug 24 Javascript
javascript中强制执行toString()具体实现
Apr 27 Javascript
js监听鼠标事件控制textarea输入字符串的个数
Sep 29 Javascript
jquery实现select选择框内容左右移动代码分享
Nov 21 Javascript
jQuery ajax提交Form表单实例(附demo源码)
Apr 06 Javascript
bootstrap table 数据表格行内修改的实现代码
Feb 13 Javascript
解决JSON.stringify()自动将中文转译成unicode的问题
Jan 05 Javascript
ES6中异步对象Promise用法详解
Jul 31 Javascript
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 向右侧拉菜单实现代码,测试使用中
2009/11/03 PHP
php操作csv文件代码实例汇总
2014/09/22 PHP
PHP的swoole扩展安装方法详细教程
2016/05/18 PHP
Laravel框架实现调用百度翻译API功能示例
2019/05/30 PHP
不错的JS中变量相关的细节分析
2007/08/13 Javascript
Js,alert出现乱码问题的解决方法
2013/06/19 Javascript
jQuery固定元素插件scrolltofixed使用指南
2015/04/21 Javascript
JS实现转动随机数抽奖特效代码
2020/04/16 Javascript
高效利用Angular中内置服务$http、$location等
2016/03/22 Javascript
Bootstrap被封装的弹层
2016/07/20 Javascript
第一次接触神奇的Bootstrap表单
2016/07/27 Javascript
Three.js快速入门教程
2016/09/09 Javascript
js document.getElementsByClassName的使用介绍与自定义函数
2016/11/25 Javascript
使用vue.js2.0 + ElementUI开发后台管理系统详细教程(一)
2017/01/21 Javascript
js实现图片旋转 js滚动鼠标中间对图片放大缩小
2017/07/05 Javascript
使用pkg打包Node.js应用的方法步骤
2018/10/19 Javascript
详解在不使用ssr的情况下解决Vue单页面SEO问题
2018/11/08 Javascript
基于vue实现一个禅道主页拖拽效果
2019/05/27 Javascript
微信小程序以ssm做后台开发的实现示例
2020/04/08 Javascript
JavaScript cookie原理及使用实例
2020/05/08 Javascript
解决element-ui里的下拉多选框 el-select 时,默认值不可删除问题
2020/08/14 Javascript
vue从后台渲染文章列表以及根据id跳转文章详情详解
2020/12/14 Vue.js
python比较两个列表大小的方法
2015/07/11 Python
python 表达式和语句及for、while循环练习实例
2017/07/07 Python
Python使用ffmpy将amr格式的音频转化为mp3格式的例子
2019/08/08 Python
浅谈Django QuerySet对象(模型.objects)的常用方法
2020/03/28 Python
python requests.get带header
2020/05/05 Python
python和go语言的区别是什么
2020/07/20 Python
CSS3中的Transition过度与Animation动画属性使用要点
2016/05/20 HTML / CSS
HTML5 通信API 跨域门槛将不再高、数据推送也不再是梦
2013/04/25 HTML / CSS
伯克斯奥特莱斯:Burkes Outlet
2019/03/30 全球购物
升旗仪式主持词
2014/03/19 职场文书
离婚被告答辩状
2015/05/22 职场文书
《领导干部从政道德启示录》学习心得体会
2016/01/20 职场文书
简历中的自我评价应该这样写!
2019/07/12 职场文书
深入理解redis中multi与pipeline
2021/06/02 Redis