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 相关文章推荐
jquery中的$(document).ready()与window.onload的区别
Nov 18 Javascript
使用js操作cookie的一点小收获分享
Sep 03 Javascript
Jquery在指定DIV加载HTML示例代码
Feb 17 Javascript
JS实现兼容性较好的随屏滚动效果
Nov 09 Javascript
jQuery实现简单隔行变色的方法
Feb 20 Javascript
js实现京东轮播图效果
Jun 30 Javascript
解决canvas画布使用fillRect()时高度出现双倍效果的问题
Aug 03 Javascript
浅析Vue中method与computed的区别
Mar 06 Javascript
vue+VeeValidate 校验范围实例详解(部分校验,全部校验)
Oct 19 Javascript
使用axios发送post请求,将JSON数据改为form类型的示例
Oct 31 Javascript
vue视频播放插件vue-video-player的具体使用方法
Nov 08 Javascript
JavaScript异步操作中串行和并行
Nov 20 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/06/01 PHP
PHP函数getenv简介和使用实例
2014/05/12 PHP
ThinkPHP结合ajax、Mysql实现的客户端通信功能代码示例
2014/06/23 PHP
php基于base64解码图片与加密图片还原实例
2014/11/03 PHP
php创建session的方法实例详解
2015/01/27 PHP
ThinkPHP的常用配置选项汇总
2016/03/24 PHP
php查看一个变量的占用内存的实例代码
2020/03/29 PHP
Javascript图像处理—虚拟边缘介绍及使用方法
2012/12/27 Javascript
谷歌浏览器不支持showModalDialog模态对话框的解决方法
2014/09/22 Javascript
使用JS实现jQuery的addClass, removeClass, hasClass函数功能
2014/10/31 Javascript
Javascript无参数和有参数类继承问题解决方法
2015/03/02 Javascript
jquery简单的弹出层浮动层代码
2015/04/27 Javascript
一览画面点击复选框后获取多个id值的方法
2016/05/30 Javascript
Javascript表单特效之十大常用原理性样例代码大总结
2016/07/12 Javascript
微信开发 微信授权详解
2016/10/21 Javascript
javascript的document中的动态添加标签实现方法
2016/10/24 Javascript
微信小程序 详解下拉加载与上拉刷新实现方法
2017/01/13 Javascript
JS实现的数字格式化功能示例
2017/02/10 Javascript
bootstrap响应式表格实例详解
2017/05/15 Javascript
Node.js中环境变量process.env的一些事详解
2017/10/26 Javascript
vue做移动端适配最佳解决方案(亲测有效)
2018/09/04 Javascript
基于Koa2写个脚手架模拟接口服务的方法
2018/11/27 Javascript
[19:59]2014DOTA2国际邀请赛 IG战队纪录片
2014/08/07 DOTA
[02:10]DOTA2 TI10勇士令状玩法及不朽Ⅰ展示:焕新世界,如你所期
2020/05/29 DOTA
Python 使用SMTP发送邮件的代码小结
2016/09/21 Python
python简单线程和协程学习心得(分享)
2017/06/14 Python
Python整数对象实现原理详解
2019/07/01 Python
python被修饰的函数消失问题解决(基于wraps函数)
2019/11/04 Python
python3.7.3版本和django2.2.3版本是否可以兼容
2020/09/01 Python
CSS+jQuery实现的在线答题功能
2015/04/25 HTML / CSS
CSS3实现鼠标悬停显示扩展内容
2016/08/24 HTML / CSS
妇女干部培训方案
2014/05/12 职场文书
环保倡议书50字
2014/05/15 职场文书
年度优秀员工获奖感言
2014/08/15 职场文书
实训报告范文大全
2014/11/04 职场文书
换届选举主持词
2015/07/03 职场文书