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 后缀名判断限制代码
Mar 31 NodeJs
Ubuntu中搭建Nodejs开发环境过程分享
Jun 01 NodeJs
nodejs npm包管理的配置方法及常用命令介绍
Jun 05 NodeJs
NodeJS创建基础应用并应用模板引擎
Apr 12 NodeJs
Nodejs搭建wss服务器教程
May 24 NodeJs
使用npm安装最新版本nodejs
Jan 18 NodeJs
PHPStorm中如何对nodejs项目进行单元测试详解
Feb 28 NodeJs
详解nodejs http请求相关总结
Mar 31 NodeJs
通过Nodejs搭建网站简单实现注册登录流程
Jun 14 NodeJs
通过实例了解Nodejs模块系统及require机制
Jul 16 NodeJs
如何利用nodejs自动定时发送邮件提醒(超实用)
Dec 01 NodeJs
Nodejs 数组的队列以及forEach的应用详解
Feb 25 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
关于file_get_contents返回为空或函数不可用的解决方案
2013/06/24 PHP
帝国CMS留言板回复后发送EMAIL通知客户
2015/07/06 PHP
Win7环境下Apache连接MySQL提示连接已重置的解决办法
2017/05/09 PHP
PHP实现实时生成并下载超大数据量的EXCEL文件详解
2017/10/23 PHP
JavaScript在IE和Firefox浏览器下的7个差异兼容写法小结
2010/06/18 Javascript
js对象的比较
2011/02/26 Javascript
js切换div css注意的细节
2012/12/10 Javascript
js 自动播放的实例代码
2013/11/19 Javascript
jquery、js调用iframe父窗口与子窗口元素的方法整理
2014/07/31 Javascript
jQuery Ajax()方法使用指南
2014/11/19 Javascript
js+css实现tab菜单切换效果的方法
2015/01/20 Javascript
网站发布后Bootstrap框架引用woff字体无法正常显示的解决方法
2016/11/24 Javascript
JavaScript+Html5实现按钮复制文字到剪切板功能(手机网页兼容)
2017/03/30 Javascript
Node.js使用Koa搭建 基础项目
2018/01/08 Javascript
vue获取验证码倒计时组件
2019/08/26 Javascript
jquery validate 实现动态增加/删除验证规则操作示例
2019/10/28 jQuery
Javascript表单序列化原理及实现代码详解
2020/10/30 Javascript
Vue 的 v-model用法实例
2020/11/23 Vue.js
Python linecache.getline()读取文件中特定一行的脚本
2008/09/06 Python
python命令行参数解析OptionParser类用法实例
2014/10/09 Python
跟老齐学Python之类的细节
2014/10/13 Python
Python解析json文件相关知识学习
2016/03/01 Python
Python箱型图绘制与特征值获取过程解析
2019/10/22 Python
使用python实现男神女神颜值打分系统(推荐)
2019/10/31 Python
python 安装库几种方法之cmd,anaconda,pycharm详解
2020/04/08 Python
CSS3 transition 实现通知消息轮播条
2020/10/14 HTML / CSS
博朗(Braun)俄罗斯官方商店:德国小家电品牌
2019/09/24 全球购物
C语言面试题
2013/05/19 面试题
AssertionError 跟一下那个类是 “is – a”的关系
2012/02/21 面试题
预备党员承诺书
2014/03/25 职场文书
无偿献血倡议书
2014/04/14 职场文书
党的群众路线教育实践活动个人承诺书
2014/05/22 职场文书
本科应届生自荐信
2014/06/29 职场文书
党的群众路线对照检查材料思想汇报
2014/09/25 职场文书
教师节老师寄语
2015/05/28 职场文书
初中数学教学随笔
2015/08/15 职场文书