Node.js mm131图片批量下载爬虫1.01 增加断点续传功能

2023-05-16

这里的断点续传不是文件下载时的断点续传,而是指在爬行页面时有时会遇到各种网络中断而从中断前的页面及其数据继续爬行的过程,这个过程和断点续传原理上相似故以此命名。我的具体做法是:在下载出现故障或是图片已经全部获得时,将存储目录,当前爬行页面和已经获取的图片地址以json形式存储到数据文件中,而用户选择断点续传模式时提取数据文件中的这三条信息,继而从上次中断之处重新运行。

数据文件示例:


{"url":"http://m.03122.com/gaoqing/9353/27.html","pictures":["http://img.cdjqjy.com/pic/gqimg/94/b36ab1a61b3c19d84386ed69ffcdad16.jpg","http://img.cdjqjy.com/pic/gqimg/94/fd4b2a40df592105725d7374f101d86c.jpg","http://img.cdjqjy.com/pic/gqimg/94/cd742a03afa54603d39b2a0d67190cfb.jpg","http://img.cdjqjy.com/pic/gqimg/94/69493144d80120ce1631d98b77ab667a.jpg"],"folder":"pictures(2017-11-18 15_5_31)"}  

 

Node.js 代码如下:


//======================================================
// mm131图片批量下载爬虫1.01
// 1.00 具备功能
// 1.01 增加断点续传
// 2017年11月15日
//======================================================

// 内置http模块
var http=require("http");

// 内置文件处理模块,用于创建目录和图片文件
var fs=require('fs');

// 用于转码。非Utf8的网页如gb2132会有乱码问题,需要iconv将其转码
var iconv = require('iconv-lite');

// cheerio模块,提供了类似jQuery的功能,用于从HTML code中查找图片地址和下一页
var cheerio = require("cheerio");

// 请求参数JSON。http和https都有使用
var options;

// request请求
var req;

// 图片数组,找到的图片地址会放到这里
var pictures=[];

// 存放图片的目录
var folder="";

//--------------------------------------
// 爬取网页,找图片地址,再爬
// pageUrl sample:http://www.mm131.com/xinggan/2852.html
// pageUrl sample:http://www.mm131.com/xinggan/2853.html
// pageUrl sample:http://www.mm131.com/xinggan/2976.html  
//--------------------------------------
function crawl(pageUrl){
    console.log("Current page="+pageUrl);

    // 得到hostname和path
    var currUrl=pageUrl.replace("http://","");
    var pos=currUrl.indexOf("/");
    var hostname=currUrl.slice(0,pos);        
    var path=currUrl.slice(pos);    
    //console.log("hostname="+hostname);
    //console.log("path="+path);
    
    // 初始化options  
    options={
        hostname:hostname,
            port:80,
            path:path,// 子路径
          method:'GET',        
    };

    req=http.request(options,function(resp){
        var html = [];

        resp.on("data", function(data) {
            html.push(data);
        })
        resp.on("end", function() {
            var buffer = Buffer.concat(html);
            var body = iconv.decode(buffer,'gb2312'); // 特地增加的,为了让汉字不乱码
            //console.log(body);
            
            var $ = cheerio.load(body);        
            var picCount=0;

            // 找图片放入数组
            $(".content-pic a img").each(function(index,element){
                var picUrl=$(element).attr("src");
                //console.log(picUrl);

                if(picUrl.indexOf('.jpg')!=-1){
                    pictures.push(picUrl); 
                    picCount++;
                } 
            })   
            console.log("找到图片"+picCount+"张.");                
            
            var nextPageUrl=null;
            // 找下一页
            $(".content-page a").each(function(index,element){
                var text=$(element).text();
                if(text.indexOf('下一页')!=-1){
                    nextPageUrl=$(element).attr("href");
                    nextPageUrl="http://www.mm131.com/xinggan/"+nextPageUrl;// 把省略部分加上
                    console.log("找到下一页.");
                }         
            })

            if(nextPageUrl==null){
                console.log(pageUrl+"已经是最后一页了.\n");
                saveFile(pageUrl,pictures);// 保存
                download(pictures);
            }else{
                //console.log("下一页是"+nextPageUrl);
                crawl(nextPageUrl);
            }
            
        }).on("error", function() {
            saveFile(pageUrl,pictures);// 保存
            console.log("crawl函数失败,请进入断点续传模式继续进行");
        })
    });

    // 超时处理
    req.setTimeout(7500,function(){
        req.abort();
    });

    // 出错处理
    req.on('error',function(err){
        console.log('请求发生错误'+err);  
        saveFile(pageUrl,pictures);// 保存
        console.log("crawl函数失败,请进入断点续传模式继续进行");
    });

    // 请求结束
    req.end();
}

//--------------------------------------
// 下载图片
//--------------------------------------
function download(pictures){

    var total=0;
    total=pictures.length;
    console.log("总计有"+total+"张图片将被下载.");
    appendToLogfile(folder,"总计有"+total+"张图片将被下载.\n");
    for(var i=0;i<pictures.length;i++){
        var picUrl=pictures[i];
        downloadPic(picUrl,folder);
    }
}

//--------------------------------------
// 写log文件
//--------------------------------------
function appendToLogfile(folder,text){
    fs.appendFile('./'+folder+'/log.txt', text, function (err) {
        if(err){
            console.log("不能书写log文件");
            console.log(err);
        }
    });
}

//--------------------------------------
// 取得当前时间
//--------------------------------------
function getNowFormatDate() {
    var date = new Date();
    var seperator1 = "-";
    var seperator2 = "_";
    var month = date.getMonth() + 1;
    var strDate = date.getDate();
    if (month >= 1 && month <= 9) {
        month = "0" + month;
    }
    if (strDate >= 0 && strDate <= 9) {
        strDate = "0" + strDate;
    }
    var currentdate =date.getFullYear() + seperator1 + month + seperator1 + strDate
            + " " + date.getHours() + seperator2 + date.getMinutes()
            + seperator2 + date.getSeconds();
    return currentdate;
}

//--------------------------------------
// 下载单张图片
// picUrl sample:http://img2.mm131.com:55888/pic/2852/1.jpg
//--------------------------------------
function downloadPic(picUrl,folder){
    console.log("图片:"+picUrl+"下载开始");

    // 得到hostname,path和port
    var currUrl=picUrl.replace("http://","");
    var pos=currUrl.indexOf("/");
    var hostname=currUrl.slice(0,pos);        
    var path=currUrl.slice(pos);

    // 有端口加端口,没有端口默认80
    var port=80;
    if(hostname.indexOf(":")!=-1){
        var arr=hostname.split(":");
        hostname=arr[0];
        port=arr[1];
    }    

    //console.log("hostname="+hostname);
    //console.log("path="+path);
    //console.log("port="+port);

    var picName=currUrl.slice(currUrl.lastIndexOf("/"));
    
    // 初始化options  
    options={
        hostname:hostname,
            port:port,
            path:path,// 子路径
          method:'GET',
              headers:{
                  'Referer':'http://www.mm131.com',      
            }
    };

    req=http.request(options,function(resp){
        var imgData = "";
        resp.setEncoding("binary"); 

        resp.on('data',function(chunk){
            imgData+=chunk;            
        });

        resp.on('end',function(){        

            // 创建文件
            var fileName="./"+folder+picName;
            fs.writeFile(fileName, imgData, "binary", function(err){
                if(err){
                    console.log("[downloadPic]文件   "+fileName+"  下载失败.");
                    console.log(err);
                    appendToLogfile(folder,"文件  "+picUrl+"  下载失败.\n");
                }else{
                    appendToLogfile(folder,"文件  "+picUrl+"  下载成功.\n");
                    console.log("文件"+fileName+"下载成功");
                }
            });    
        });
    });

    // 超时处理
    req.setTimeout(7500,function(){
        req.abort();
    });

    // 出错处理
    req.on('error',function(err){
        if(err){
            console.log('[downloadPic]文件   '+picUrl+"  下载失败,"+'因为'+err);
            appendToLogfile(folder,"文件"+picUrl+"下载失败.\n");
        }
    });

    // 请求结束
    req.end();
}

//--------------------------------------
// 程序入口 
//--------------------------------------
function getInput(){
    process.stdin.resume();    
    process.stdout.write("\033[33m 新建模式输入第一页URL,断点续传模式输入0,请输入: \033[39m");// 草黄色
    process.stdin.setEncoding('utf8');
    
    process.stdin.on('data',function(text){
        var input=text.trim();
        process.stdin.end();// 退出输入状态    

        if(text.trim()=='0'){
            process.stdout.write("\033[36m 进入断点续传模式. \033[39m");    // 蓝绿色

            // Read File
            fs.readFile('./save.dat','utf8',function(err,data){
                if(err){
                    console.log('读取文件save.dat失败,因为'+err);
                }else{
                    //console.log(data);
                    var obj=JSON.parse(data);

                    pictures=obj.pictures;
                    console.log('提取图片'+pictures.length+'张');

                    folder=obj.folder;

                    // 创建目录
                    fs.mkdir('./'+folder,function(err){
                        if(err){
                            console.log("目录"+folder+"已经存在");
                        }
                    });

                    crawl(obj.url);        
                }
            });
            
            // Resume crawl
        }else{
            process.stdout.write("\033[35m 进入新建模式. \033[039m");    //紫色

            folder='pictures('+getNowFormatDate()+")";
            // 创建目录
            fs.mkdir('./'+folder,function(err){
                if(err){
                    console.log("目录"+folder+"已经存在");
                }
            });

            crawl(input);            
        }
    });    
}

//--------------------------------------
// 将爬行中信息存入数据文件
//--------------------------------------
function saveFile(url,pictures){
    var obj=new Object;
    obj.url=url;
    obj.pictures=pictures;
    obj.folder=folder;
    var text=JSON.stringify(obj);

    fs.writeFile('./save.dat',text,function(err){
        if(err){
            console.log('写入文件save.dat失败,因为'+err);
        }
    });
}

// 调用getInput函数,程序开始
getInput();  

2017年11月16日

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Node.js mm131图片批量下载爬虫1.01 增加断点续传功能 的相关文章

  • 16核64g服务器性能,16核64g云服务器

    16核64g云服务器 内容精选 换一换 用户可以查看在不同云服务区已经申请成功的专属云 进入指定的专属云 xff0c 还可以查看该专属云内专属计算资源详情及云服务器等专属云内基础服务的实例信息 登录管理控制台 单击左侧上方区域下拉列表 xf
  • 集成测试:自底向上、自顶向下、Big-Bang集成测试、三明治集成测试

    集成测试 xff1a 自底向上 自顶向下 Big Bang集成测试 三明治集成测试 详解测试过程测试方案自顶向下自底向上三明治测试Big Bang集成测试 详解 集成测试也叫组装测试或者联合测试 xff0c 在单元测试完成的基础上进行模块
  • cloudtalk 无法连接到消息服务器,solr - Solr Cloud down无法与Zookeeper对话客户端会话超时 - 堆栈内存溢出...

    我有在16GB RAM内存上运行的solr云 xff0c 用于分片的2个solr节点 相同ip xff0c 嵌入式zookeeper 我在默认配置上运行solr xff0c 尽管默认配置随附 Xms5g Xmx5g xff0c 但我在Sol
  • 网站服务器备案有什么危害,域名备案对服务器有影响吗

    域名备案对服务器有影响吗 内容精选 换一换 证书在有效期内 xff0c 可多次下载并使用 xff0c 下载后即可在服务器 华为云的或非华为云的均可 上进行部署 待安装证书的服务器上需要运行的域名 xff0c 必须与证书的域名一一对应 xff
  • lodash 核心源码学习(基于4.17.11版本)

    源码地址 https raw githubusercontent com lodash lodash 4 17 11 npm core js 13行 b var undefined b es5之前 undefined 可以被 window
  • 常用邮箱的 IMAP/POP3/SMTP 设置

    通过网上查找的资料和自己的总结完成了下面的文章 xff0c 看完之后相信大家对这三种协议会有更深入的理解 如有错误的地方望指正 POP3 POP3是Post Office Protocol 3的简称 xff0c 即邮局协议的第3个版本 它规
  • 顾维灏谈百度地图数据采集:POI自动处理率达90%

    顾维灏谈百度地图数据采集 xff1a POI自动处理率达90 发布时间 xff1a 2015 12 21 22 37 来源 xff1a cnsoftnews com 作者 xff1a 百度地图还创新研发高精地图 xff0c 并成为国内唯一掌
  • 为何float有效位数为7位?

    为何float有效位数为7位 xff1f 首先我们应该明确一点 xff1a C语言中 xff0c xff05 f表示保留7位有效数字7位有效数字 xff1a 是指 整数部分 和小数部分一共7位 单精度数的尾数用23位存储 xff0c 加上默
  • Python绘制正余弦函数图像

    公众号 xff1a Python编程时光 今天打算通过绘制正弦和余弦函数 xff0c 从默认的设置开始 xff0c 一步一步地调整改进 xff0c 让它变得好看 xff0c 变成我们初高中学习过的图象那样 通过这个过程来学习如何进行对图表的
  • JS函数的工厂模式、构造函数模式、原型模式的区别

    创建对象 JS有六种数据数据类型 xff0c 其中五种属于基本数据类型 xff1a Null Boolean undefined String Number 而其它值都是对象 数组是对象 xff0c 函数是对象 xff0c 正则表达式是对象
  • mac 邮件自动归类

    mac 让邮箱自动为你的邮件归类 不知道你的工作当中 xff0c 是否每天会收到一大推的邮件 xff0c 其中对自己有价值的邮件也许也就是这一大推邮件当中的几封邮件 单这几封邮件往往又会被淹没 巧用邮件分类功能 之前使用邮件没有好好的区研究
  • 层次图和HIPO图---描绘软件结构的图形工具

    层次图和HIPO 图 层次图用来描述软件的层次结构 虽然层次图的形式和描绘数据结构的层次方框图相同 xff0c 但是表现的内容却完全不同 层次图中的一个矩形框代表一个模块 xff0c 方框间的连线表示调用关系而不像层次方框图那样表示组成关系
  • continue函数和break函数的区别

    continue函数 谈及contiune函数 xff0c 很多初学者都把它和break弄混淆 xff0c 今天我自己也特意学习了一下 xff0c 在这里分享给大家 当它们用在循环语句的循环体时 xff0c break用于立即退出本层循环
  • linux下进入root用户登录

    1 打开终端 xff0c 输入sudo passwd u root 输入当前用户的登录密码 xff0c 提示如下标红区域信息 解决方案 xff1a 1 xff09 直接输入命令 xff1a su xff0c 输入当前用户登录密码 2 xff
  • 利用Python爬取电影网站

    usr bin env python coding 61 utf 8 39 39 39 本爬虫是用来爬取6V电影网站上的电影资源的一个小脚本程序 xff0c 爬取到的电影链接会通过网页的形式显示出来 39 39 39 import requ
  • python 提取字符串中的数字组成新的字符串

    方法一 有一个字符串text 61 34 aAsmr3idd4bgs7Dlsf9eAF 34 请将text字符串中的数字取出 xff0c 并输出成一个新的字符串 import re text 61 34 aAsmr3idd4bgs7Dlsf
  • Trie树

    转载自http epic 32o cn article asp id 61 47 xff0c 但是这个地址已经不存在了 所以从维基百科拿来个图进行解释 xff1a http zh wikipedia org wiki Trie 今天在vij
  • 【C#学习笔记】读SQL Server2008

    using System using System Data SqlClient namespace ConsoleApplication class Program static void Main string args SqlConn
  • window class, OO

    Wndows中Window Management 的设计 是很符合OO思想 首先每个Window的定义由WNDCLASS结构定义 在WNDCLASS中我们需要给出 Window class name Window的class style 以
  • regex_match

    原型 xff1a bool regex match InputSequence MatchResults Regex Flags 当模式匹配整个输入序列成功时 xff0c 返回的是true 否则返回false 参数说明 1 InputSeq

随机推荐

  • 关于Docker目录挂载的总结

    Docker容器启动的时候 xff0c 如果要挂载宿主机的一个目录 xff0c 可以用 v参数指定 譬如我要启动一个centos容器 xff0c 宿主机的 test目录挂载到容器的 soft目录 xff0c 可通过以下方式指定 xff1a
  • Wireshark网络抓包(一)——数据包、着色规则和提示

    一 数据包详细信息 Packet Details面板内容如下 xff0c 主要用于分析封包的详细信息 帧 xff1a 物理层 链路层 包 xff1a 网络层 段 xff1a 传输层 应用层 1 xff09 Frame 物理层数据帧概况 2
  • FloatingWindow 悬浮窗开源项目总结

    在Android开发中 xff0c 我们不免会遇到悬浮窗展示的需求 xff0c 以下是本人之前star的悬浮窗的开源项目 xff0c 供大家参考 xff1a 一 FloatingWindowDemo 开源项目地址 xff1a https g
  • yum-config-manager的讲解

    问题描述 xff1a yum是RPM的前端程序 xff0c 对于多软件安装时非常好用 xff0c 在虚拟机中想要安装什么软件都可以使用 yum install xff1a 仓库名 命令来快速调用已经安装的仓库里的软件 xff0c 但有时在安
  • 1024与自己做爱做的事情

    1024是什么 xff1f 1024最早起源于一个名为 草榴社区 的论坛 xff0c 该论坛为了防止灌水 xff0c 新用户在论坛内回复与发帖时 xff0c 被限制为 每隔1024秒才可发帖 xff08 回复 xff09 一次 xff0c
  • Nervos CKB 共识协议 NC-Max:突破 Nakamoto Consensus 吞吐量的极限

    带宽实际上是区块链吞吐量的最大限制 xff0c 在美国旧金山举办的 Scaling Bitcoin Meetup 中 xff0c Nervos amp Cryptape 研究员张韧从 带宽利用率 角度分析了诸多共识协议的效率和可行性 Alg
  • ES6: import和export

    模块化 前端模块化的好处都已经被说烂了 xff0c 归纳为两点 xff1a 避免全局变量污染有效的处理依赖关系 ES2015 xff08 ES6 xff09 终于引入了模块的概念 xff0c 最近学习了下 xff0c 顺便记下笔记 准备工作
  • 6个常见校园网认证客户端故障原因及解决方法

    故障 一 xff1a 本地连接打叉或受限制 xff1b 客户端 提示 无法获取IP信息 可能原因 1 xff0e 网线虚接 2 xff0e 学生端网络 跳线质量太差 3 xff0e 网卡 或网卡驱动程序过久 4 xff0e 交换机的某个端口
  • C语言编程 求两个数的平均值方法(三种方法)

    第一种方法是最常见的 average 61 xff08 a 43 b xff09 2这种方式 xff0c 求两个数的平均值 第二种方法是 当 a lt b 时 averag 61 a 43 b a 2 这里着重介绍的是第三种方法 avera
  • IDEA创建GIT分支并提交到其他分支

    1 xff0c 创建分支 2 xff0c 提交自己的分支 3 xff0c 写代码 xff0c 写完之后切换到你想要提交的分支 xff0c 例子develop 切花分支 xff0c 选择分支 xff0c checkOut 4 下载该分支的更新
  • 【C#学习笔记】写文件

    using System using System IO namespace ConsoleApplication class Program static void Main string args FileStream file 61
  • socket编程——一个简单的例子(转)

    原文地址 xff1a http blog csdn net wind19 article details 6156339 从一个简单的使用TCP例子开始socket编程 xff0c 其基本步骤如下 xff1a server client 4
  • BI 多维数据 处理错误

    哎 响应中的错误和警告 后端数据库访问模块中存在错误 OLE DB 报告列 11 出现了数据类型溢出现象 OLAP 存储引擎中存在错误 处理 Fact Order Sales 分区时出错 xff0c 该分区属于 Analysis 数据库的
  • AutoLISPDCL各种控件

    AutoLISP对话框DCL一共包括23个常用控件和8个固定控件 xff0c 每种控件属于一种类型 xff0c 创建一个DCL对话框窗体就是创建各种控件实例的过程 xff0c 控件是各种属性 事件 方法的集合 按照各种控件的特点 xff0c
  • 完整克隆、链接克隆

    在VMware中安装虚拟主机时 xff0c 若想简便快速的部署多台虚拟主机 xff0c 可先配置一台虚拟主机的一些基础设置 xff0c 然后通过 34 克隆 34 的方式快速部署 而 34 克隆 34 又分为完整克隆和链接克隆 xff1a
  • 急求mapx控件下载!!!

    急求mapx控件下载 Delphi Windows SDK API http www delphi2007 net DelphiMultimedia html delphi 2006121723132453 html 刚刚在网上搜了好久 没
  • 【Android】Mac安装EasyTether导致无法识别设备的问题

    正文 想让手机走PC网络 xff0c 然后抓包 xff0c 于是搜索一番后安装了一个叫EasyTether的软件 还没来得及测试 xff0c 就忙着写代码去了 xff0c 重启MAC以后就发现连不上手机了 xff0c 一开始并没有怀疑是 E
  • C# 操作PDF

    Spire PDF组件概述 Spire PDF是一个专业的PDF组件 xff0c 用于在 NET应用程序中创建 xff0c 编辑 xff0c 处理和阅读PDF文档 支持丰富的PDF文档处理操作 xff0c 如PDF文档合并 拆分 转换 xf
  • 液晶显示器面板型号速查[转贴]

    原文链接 xff1a http itbbs pconline com cn topic jsp tid 61 3132291 生产厂家 显示器型号 61 面板尺寸 面板类型 xff08 面板制造商和面板型号 xff09 例 xff1a 比如
  • Node.js mm131图片批量下载爬虫1.01 增加断点续传功能

    这里的断点续传不是文件下载时的断点续传 xff0c 而是指在爬行页面时有时会遇到各种网络中断而从中断前的页面及其数据继续爬行的过程 xff0c 这个过程和断点续传原理上相似故以此命名 我的具体做法是 xff1a 在下载出现故障或是图片已经全