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 学习之一 对象访问
Nov 23 Javascript
js实现的tab标签切换效果代码分享
Aug 25 Javascript
jquery实现点击变换导航样式的方法
Aug 31 Javascript
基于javascript实现listbox左右移动
Jan 29 Javascript
js匿名函数作为函数参数详解
Jun 01 Javascript
功能强大的Bootstrap效果展示(二)
Aug 03 Javascript
jQuery源码解读之extend()与工具方法、实例方法详解
Mar 30 jQuery
JS严格模式知识点总结
Feb 27 Javascript
jQuery滚动条美化插件nicescroll简单用法示例
Apr 18 jQuery
详解js根据百度地图提供经纬度计算两点距离
May 13 Javascript
Vue 使用Props属性实现父子组件的动态传值详解
Nov 13 Javascript
使用vant的地域控件追加全部选项
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
PHP导入导出Excel代码
2015/07/07 PHP
php连接oracle数据库的核心步骤
2016/05/26 PHP
PHP mysqli_free_result()与mysqli_fetch_array()函数详解
2016/09/21 PHP
PHP输出多个元素的排列或组合的方法
2017/03/14 PHP
php获取数据库结果集方法(推荐)
2017/06/01 PHP
PHP编程中的Session阻塞问题与解决方法分析
2017/08/07 PHP
Jquery 1.42 checkbox 全选和反选代码
2010/03/27 Javascript
JS实现浏览器状态栏文字闪烁效果的方法
2015/10/27 Javascript
Javascript实现图片加载从模糊到清晰显示的方法
2016/06/21 Javascript
Vue.js Ajax动态参数与列表显示实现方法
2016/10/20 Javascript
ES6实现的遍历目录函数示例
2017/04/07 Javascript
vuejs绑定class和style样式
2017/04/11 Javascript
Angular实现点击按钮后在上方显示输入内容的方法
2017/12/27 Javascript
详解搭建es6+devServer简单开发环境
2018/09/25 Javascript
layui table去掉右侧滑动条的实现方法
2019/09/05 Javascript
Element DateTimePicker日期时间选择器的使用示例
2020/07/27 Javascript
javascript实现移动端轮播图
2020/12/09 Javascript
js实现电灯开关效果
2021/01/19 Javascript
在Python的Django框架中显示对象子集的方法
2015/07/21 Python
使用Python编写简单的画图板程序的示例教程
2015/12/08 Python
python实现读取excel写入mysql的小工具详解
2017/11/20 Python
Django的Modelforms用法简介
2019/07/27 Python
18个Python脚本可加速你的编码速度(提示和技巧)
2019/10/17 Python
Pandas数据离散化原理及实例解析
2019/11/16 Python
python中Ansible模块的Playbook的具体使用
2020/05/28 Python
python实现三壶谜题的示例详解
2020/11/02 Python
用html5绘制折线图的实例代码
2016/03/25 HTML / CSS
Math.round(11.5)等於多少? Math.round(-11.5)等於多少?
2015/01/27 面试题
倡议书范文格式
2014/05/12 职场文书
关键在于落实心得体会
2014/09/03 职场文书
村主任群众路线教育实践活动个人对照检查材料思想汇报
2014/10/01 职场文书
招商引资工作汇报材料
2014/10/28 职场文书
承德避暑山庄导游词
2015/02/03 职场文书
毕业实习感受与体会
2015/05/26 职场文书
导游词之江南周庄
2019/12/06 职场文书
如何用Laravel包含你自己的帮助函数
2021/05/27 PHP