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 相关文章推荐
基于promise.js实现nodejs的promises库
Jul 06 NodeJs
NodeJs读取JSON文件格式化时的注意事项
Sep 25 NodeJs
nodejs和php实现图片访问实时处理
Jan 05 NodeJs
NodeJS实现客户端js加密
Jan 09 NodeJs
详解nodejs中exports和module.exports的区别
Feb 17 NodeJs
nodejs实现邮件发送服务实例分享
Mar 29 NodeJs
nodejs个人博客开发第二步 入口文件
Apr 12 NodeJs
详解nodejs微信公众号开发——6.自定义菜单
Apr 13 NodeJs
NodeJS实现微信公众号关注后自动回复功能
May 31 NodeJs
NodeJS 实现手机短信验证模块阿里大于功能
Jun 19 NodeJs
nodejs实现的连接MySQL数据库功能示例
Jan 25 NodeJs
NodeJS加密解密及node-rsa加密解密用法详解
Oct 12 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模块memcache和memcached区别分析
2011/06/14 PHP
thinkPHP5.0框架整体架构总览【应用,模块,MVC,驱动,行为,命名空间等】
2017/03/25 PHP
详解php几行代码实现CSV格式文件输出
2017/07/01 PHP
php实现分页功能的详细实例方法
2019/09/29 PHP
js几个不错的函数 $$()
2006/10/09 Javascript
Javascript 面向对象 继承
2010/05/13 Javascript
javascript dom代码应用 简单的相册[firefox only]
2010/06/12 Javascript
js动态添加onload、onresize、onscroll事件(另类方法)
2012/12/26 Javascript
Javascript 按位与赋值运算符 (&amp;=)使用介绍
2014/02/04 Javascript
jquery复选框多选赋值给文本框的方法
2015/01/27 Javascript
基于jQuery实现在线选座之高铁版
2015/08/24 Javascript
JavaScript事件详细讲解
2016/06/27 Javascript
基于JS实现checkbox全选功能实例代码
2016/10/31 Javascript
JS+Canvas实现的俄罗斯方块游戏完整实例
2016/12/12 Javascript
微信JS SDK接入的几点注意事项(必看篇)
2017/06/23 Javascript
讲解vue-router之什么是编程式路由
2018/05/28 Javascript
基于React Native 0.52实现轮播图效果
2020/08/25 Javascript
小程序开发踩坑:页面窗口定位(相对于浏览器定位)(推荐)
2019/04/25 Javascript
jQuery实时统计输入框字数及限制
2020/06/24 jQuery
如何在面试中手写出javascript节流和防抖函数
2020/10/22 Javascript
从源码角度来回答keep-alive组件的缓存原理
2021/01/18 Javascript
python使用新浪微博api上传图片到微博示例
2014/01/10 Python
Python3读取zip文件信息的方法
2015/05/22 Python
Python修改MP3文件的方法
2015/06/15 Python
Python程序中的观察者模式结构编写示例
2016/05/27 Python
django mysql数据库及图片上传接口详解
2019/07/18 Python
appium+python adb常用命令分享
2020/03/06 Python
Python的控制结构之For、While、If循环问题
2020/06/30 Python
pandas apply多线程实现代码
2020/08/17 Python
PyCharm安装PyQt5及其工具(Qt Designer、PyUIC、PyRcc)的步骤详解
2020/11/02 Python
美国最大的宠物药店:1-800-PetMeds
2016/10/02 全球购物
Perfume’s Club德国官网:在线购买香水
2019/04/08 全球购物
英国比较机场停车场网站:Airport Parking Essentials
2019/12/01 全球购物
批评与自我批评总结
2014/10/17 职场文书
2015年秋季运动会加油稿
2015/07/22 职场文书
2019年“我为祖国点赞”演讲稿(3篇)
2019/09/26 职场文书