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』限制Input只能输入数字实现思路及代码
Apr 22 Javascript
jquery动态增加text元素以及删除文本内容实例代码
Jul 01 Javascript
Javascript的&amp;&amp;和||的另类用法
Jul 23 Javascript
javascript实现在某个元素上阻止鼠标右键事件的方法和实例
Aug 12 Javascript
学习vue.js中class与style绑定
Dec 03 Javascript
jQuery实现鼠标滑过图片移动特效
Dec 08 Javascript
Angularjs中ng-repeat的简单实例
Aug 25 Javascript
vue实现动态列表点击各行换色的方法
Sep 13 Javascript
jQuery选择器之基本选择器用法实例分析
Feb 19 jQuery
jquery分页优化操作实例分析
Aug 23 jQuery
Postman如何实现参数化执行及断言处理
Jul 28 Javascript
vue element和nuxt的使用技巧分享
Jan 14 Vue.js
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
德生BCL3000的电路分析和打磨
2021/03/02 无线电
PHP IN_ARRAY 函数使用注意事项
2010/07/24 PHP
php生成随机密码的几种方法
2011/01/17 PHP
PHP自动生成表单代码分享
2015/06/19 PHP
Yii框架日志记录Logging操作示例
2018/07/12 PHP
php创建多级目录与级联删除文件的方法示例
2019/09/12 PHP
js下弹出窗口的变通
2007/04/18 Javascript
Draggable Elements 元素拖拽功能实现代码
2011/03/30 Javascript
取得窗口大小 兼容所有浏览器的js代码
2011/08/09 Javascript
JQuery异步提交表单与文件上传功能示例
2017/01/12 Javascript
vue.js过滤器+ajax实现事件监听及后台php数据交互实例
2018/05/22 Javascript
小程序tab页无法传递参数的方法
2018/08/03 Javascript
详解JavaScript添加给定的标签选项
2018/09/17 Javascript
nodejs中实现修改用户路由功能
2019/05/24 NodeJs
Vue.js中的组件系统
2019/05/30 Javascript
浅析JS中NEW的实现原理及重写
2020/02/20 Javascript
解决vue动态下拉菜单 有数据未反应的问题
2020/08/06 Javascript
[02:51]DOTA2 2015国际邀请赛中国区预选赛第一日战报
2015/05/27 DOTA
Python使用Selenium爬取淘宝异步加载的数据方法
2018/12/17 Python
django框架forms组件用法实例详解
2019/12/10 Python
美国在线咖啡、茶和餐厅供应商:LollicupStore
2018/05/04 全球购物
阿拉伯书店:Jamalon
2019/07/24 全球购物
Footshop乌克兰:运动鞋的最大选择
2019/12/01 全球购物
美国体育用品商店:Academy Sports + Outdoors
2020/01/04 全球购物
一套PHP的笔试题
2013/05/31 面试题
职业生涯规划书基本格式
2014/01/06 职场文书
优秀共产党员先进事迹
2014/01/27 职场文书
户外活动策划方案
2014/03/12 职场文书
机械专业应届毕业生自荐书
2014/06/12 职场文书
推普周活动总结
2014/08/28 职场文书
2015年化妆品销售工作总结
2015/05/11 职场文书
2016年教师学习教师法心得体会
2016/01/20 职场文书
《我要的是葫芦》教学反思
2016/02/18 职场文书
2019年浪漫婚礼证婚词
2019/06/27 职场文书
读《庄子》有感:美而不自知
2019/11/06 职场文书
python 中yaml文件用法大全
2021/07/04 Python