nodeJs爬虫的技术点总结


Posted in NodeJs onMay 13, 2018

背景

最近打算把之前看过的nodeJs相关的内容在复习下,顺便写几个爬虫来打发无聊,在爬的过程中发现一些问题,记录下以便备忘。

依赖

用到的是在网上烂大街的cheerio库来处理爬取的内容,使用superagent处理请求,log4js来记录日志。

日志配置

话不多说,直接上代码:

const log4js = require('log4js');

log4js.configure({
 appenders: {
  cheese: {
   type: 'dateFile',
   filename: 'cheese.log',
   pattern: '-yyyy-MM-dd.log',
   // 包含模型
   alwaysIncludePattern: true,

   maxLogSize: 1024,
   backups: 3 }
 },
 categories: { default: { appenders: ['cheese'], level: 'info' } }
});

const logger = log4js.getLogger('cheese');
logger.level = 'INFO';

module.exports = logger;

以上直接导出一个logger对象,在业务文件里直接调用logger.info()等函数添加日志信息就可以,会按天生成日志。相关信息网络上一堆。

爬取内容并处理

superagent.get(cityItemUrl).end((err, res) => {
  if (err) {
   return console.error(err);
  }

  const $ = cheerio.load(res.text);
  // 解析当前页面,获取当前页面的城市链接地址
  const cityInfoEle = $('.newslist1 li a');
  cityInfoEle.each((idx, element) => {
   const $element = $(element);
   const sceneURL = $element.attr('href'); // 页面地址
   const sceneName = $element.attr('title'); // 城市名称
   if (!sceneName) {
    return;
   }
   logger.info(`当前解析到的目的地是: ${sceneName}, 对应的地址为: ${sceneURL}`);

   getDesInfos(sceneURL, sceneName); // 获取城市详细信息

   ep.after('getDirInfoComplete', cityInfoEle.length, (dirInfos) => {
    const content = JSON.parse(fs.readFileSync(path.join(__dirname, './imgs.json')));

    dirInfos.forEach((element) => {
     logger.info(`本条数据为:${JSON.stringify(element)}`);
     Object.assign(content, element);
    });

    fs.writeFileSync(path.join(__dirname, './imgs.json'), JSON.stringify(content));
   });
  });
 });

使用superagent请求页面,请求成功后使用cheerio 来加载页面内容,然后使用类似Jquery的匹配规则来查找目的资源。

多个资源加载完成,使用eventproxy来代理事件,处理一次资源处罚一次事件,所有事件触发完成后处理数据。

以上就是最基本的爬虫了,接下来就是一些可能会出问题或者需要特别注意的地方了。。。

读写本地文件

创建文件夹

function mkdirSync(dirname) {
 if (fs.existsSync(dirname)) {
  return true;
 }
 if (mkdirSync(path.dirname(dirname))) {
  fs.mkdirSync(dirname);
  return true;
 }

 return false;
}

读写文件

const content = JSON.parse(fs.readFileSync(path.join(__dirname, './dir.json')));

   dirInfos.forEach((element) => {
    logger.info(`本条数据为:${JSON.stringify(element)}`);
    Object.assign(content, element);
   });

   fs.writeFileSync(path.join(__dirname, './dir.json'), JSON.stringify(content));

批量下载资源

下载资源可能包括图片、音频等等。

使用Bagpipe处理异步并发 参考

const Bagpipe = require('bagpipe');

const bagpipe = new Bagpipe(10);

  bagpipe.push(downloadImage, url, dstpath, (err, data) => {
   if (err) {
    console.log(err);
    return;
   }
   console.log(`[${dstpath}]: ${data}`);
  });

下载资源,使用stream来完成文件写入。

function downloadImage(src, dest, callback) {
 request.head(src, (err, res, body) => {
  if (src && src.indexOf('http') > -1 || src.indexOf('https') > -1) {
   request(src).pipe(fs.createWriteStream(dest)).on('close', () => {
    callback(null, dest);
   });
  }
 });
}

编码

有时候直接使用 cheerio.load处理的网页内容,写入文件后发现是编码后的文字,可以通过

const $ = cheerio.load(buf, { decodeEntities: false });

来禁止编码,

ps: encoding库和iconv-lite未能实现将utf-8编码的字符转换为中文,可能是还对API不熟悉,稍后可以关注下。

最后,附上一个匹配所有dom标签的正则

const reg = /<.*?>/g;
NodeJs 相关文章推荐
nodejs中exports与module.exports的区别详细介绍
Jan 14 NodeJs
14款NodeJS Web框架推荐
Jul 11 NodeJs
nodejs批量修改文件编码格式
Jan 22 NodeJs
nodejs中的fiber(纤程)库详解
Mar 24 NodeJs
nodejs爬虫抓取数据之编码问题
Jul 03 NodeJs
浅谈Nodejs观察者模式
Oct 13 NodeJs
nodejs个人博客开发第三步 载入页面
Apr 12 NodeJs
Nodejs之TCP服务端与客户端聊天程序详解
Jul 07 NodeJs
浅谈nodejs中的类定义和继承的套路
Jul 26 NodeJs
用nodejs实现json和jsonp服务的方法
Aug 25 NodeJs
nodejs使用redis作为缓存介质实现的封装缓存类示例
Feb 07 NodeJs
nodejs实现超简单生成二维码的方法
Mar 17 NodeJs
修改Nodejs内置的npm默认配置路径方法
May 13 #NodeJs
nodejs取得当前执行路径的方法
May 13 #NodeJs
详解Nodejs内存治理
May 13 #NodeJs
nodejs更改项目端口号的方法
May 13 #NodeJs
利用nodeJs anywhere搭建本地服务器环境的方法
May 12 #NodeJs
NodeJs搭建本地服务器之使用手机访问的实例讲解
May 12 #NodeJs
nodejs 简单实现动态html的方法
May 12 #NodeJs
You might like
PHP生成随机数的方法实例分析
2015/01/22 PHP
PHP中把有符号整型转换为无符号整型方法
2015/05/27 PHP
PHP fopen中文文件名乱码问题解决方案
2020/10/28 PHP
JS location几个方法小姐
2008/07/09 Javascript
jqPlot jquery的页面图表绘制工具
2009/07/25 Javascript
jquery实现固定顶部导航效果(仿蘑菇街)
2013/03/21 Javascript
为什么要在引入的css或者js文件后面加参数的详细讲解
2013/05/03 Javascript
JavaScript字符串对象fromCharCode方法入门实例(用于把Unicode值转换为字符串)
2014/10/17 Javascript
JavaScript使用slice函数获取数组部分元素的方法
2015/04/06 Javascript
JS更改select内option属性的方法
2015/10/14 Javascript
js实现文字跑马灯效果
2017/02/23 Javascript
微信小程序页面开发注意事项整理
2017/05/18 Javascript
原生JS实现日历组件的示例代码
2017/09/22 Javascript
JavaScript设计模式之建造者模式实例教程
2018/07/02 Javascript
JavaScript接口实现方法实例分析
2020/05/16 Javascript
[01:06:25]Secret vs Liquid 2018国际邀请赛淘汰赛BO3 第一场 8.25
2018/08/29 DOTA
在Python的Django框架中获取单个对象数据的简单方法
2015/07/17 Python
利用python程序帮大家清理windows垃圾
2017/01/15 Python
Python编程实现数学运算求一元二次方程的实根算法示例
2017/04/02 Python
python 输出所有大小写字母的方法
2019/01/02 Python
详解利用Python scipy.signal.filtfilt() 实现信号滤波
2019/06/05 Python
Python面向对象之Web静态服务器
2019/09/03 Python
详解PyQt5信号与槽的几种高级玩法
2020/03/24 Python
Python BeautifulReport可视化报告代码实例
2020/04/13 Python
python exit出错原因整理
2020/08/31 Python
解决pycharm不能自动保存在远程linux中的问题
2021/02/06 Python
中东奢侈品市场:Coveti
2019/05/12 全球购物
Subside Sports德国:足球球衣和球迷商品
2019/06/08 全球购物
Java里面如何把一个Array数组转换成Collection, List
2013/07/26 面试题
南京迈特望C/C++面试题
2012/07/09 面试题
一些网络技术方面的面试题
2014/05/01 面试题
小学优秀班主任事迹材料
2014/05/17 职场文书
抗震救灾标语
2014/06/26 职场文书
个人党性锻炼总结
2015/03/05 职场文书
Nginx图片服务器配置之后图片访问404的问题解决
2022/03/21 Servers
python运行脚本文件的三种方法实例
2022/06/25 Python