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 jQuery插件练习
Dec 24 Javascript
在jquery boxy中添加百度地图坐标拾取注意流程
Apr 03 Javascript
浅析JS运动
Dec 28 Javascript
jquery对复选框(checkbox)的操作汇总
Jan 13 Javascript
微信支付 JS API支付接口详解
Jul 11 Javascript
AngularJS入门教程之Cookies读写操作示例
Nov 02 Javascript
Vue.js双向绑定操作技巧(初级入门)
Dec 27 Javascript
原生js实现简单的Ripple按钮实例代码
Mar 24 Javascript
jQuery用户头像裁剪插件cropbox.js使用详解
Jun 07 jQuery
Vue表单类的父子组件数据传递示例
May 03 Javascript
angular5 子组件监听父组件传入值的变化方法
Sep 30 Javascript
React Native登录之指纹登录篇的示例代码
Nov 03 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
索尼SONY ICF-7600A(W)电路分析
2021/03/01 无线电
网页游戏开发入门教程三(简单程序应用)
2009/11/02 PHP
PHP基于Redis消息队列实现发布微博的方法
2017/05/03 PHP
windows环境下使用Composer安装ThinkPHP5
2018/05/18 PHP
javascript网页关闭时提醒效果脚本
2008/10/22 Javascript
javascript &amp;&amp;和||运算法的另类使用技巧
2009/11/28 Javascript
jquery ajax提交表单数据的两种实现方法
2010/04/29 Javascript
如何在指定的地方插入html内容和文本内容
2013/12/23 Javascript
javascript模拟评分控件实现方法
2015/05/13 Javascript
Vue.js在使用中的一些注意知识点
2017/04/29 Javascript
Easyui在treegrid添加控件的实现方法
2017/06/23 Javascript
vue项目中使用axios上传图片等文件操作
2017/11/02 Javascript
原生JS实现的双色球功能示例
2018/02/02 Javascript
在 Angular-cli 中使用 simple-mock 实现前端开发 API Mock 接口数据模拟功能的方法
2018/11/28 Javascript
JS co 函数库的含义和用法实例总结
2020/04/08 Javascript
微信小程序实现组件顶端固定或底端固定效果(不随滚动而滚动)
2020/04/09 Javascript
vscode 插件开发 + vue的操作方法
2020/06/05 Javascript
[03:06]3分钟带你回顾DOTA2完美盛典&完美大师赛
2017/12/06 DOTA
python 自动提交和抓取网页
2009/07/13 Python
使用Django Form解决表单数据无法动态刷新的两种方法
2017/07/14 Python
Django+JS 实现点击头像即可更改头像的方法示例
2018/12/26 Python
详解Python中的正斜杠与反斜杠
2019/08/09 Python
django自带serializers序列化返回指定字段的方法
2019/08/21 Python
细数nn.BCELoss与nn.CrossEntropyLoss的区别
2020/02/29 Python
python为什么要安装到c盘
2020/07/20 Python
CSS3中的clip-path使用攻略
2015/08/03 HTML / CSS
HTML5本地存储localStorage、sessionStorage基本用法、遍历操作、异常处理等
2014/05/08 HTML / CSS
HTML5 Canvas实现烟花绽放特效
2016/03/02 HTML / CSS
伊利莎白雅顿官网:Elizabeth Arden
2016/10/10 全球购物
苏格兰销售女装、男装和童装的连锁店:M&Co
2018/03/16 全球购物
英国奢侈品在线精品店:Hervia
2020/09/03 全球购物
2014年设备管理工作总结
2014/11/26 职场文书
2015年文员个人工作总结
2015/04/09 职场文书
2019奶茶店创业计划书范本!
2019/07/15 职场文书
解析Java异步之call future
2021/06/14 Java/Android
Java Dubbo框架知识点梳理
2021/06/26 Java/Android