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 相关文章推荐
抛弃Nginx使用nodejs做反向代理服务器
Jul 17 NodeJs
Nodejs实现多人同时在线移动鼠标的小游戏分享
Dec 06 NodeJs
nodejs创建web服务器之hello world程序
Aug 20 NodeJs
nodejs修复ipa处理过的png图片
Feb 17 NodeJs
详解nodejs 文本操作模块-fs模块(一)
Dec 22 NodeJs
详解Nodejs的timers模块
Dec 22 NodeJs
详解nodejs微信公众号开发——1.接入微信公众号
Apr 10 NodeJs
nodejs个人博客开发第六步 数据分页
Apr 12 NodeJs
nodejs实现OAuth2.0授权服务认证
Dec 27 NodeJs
nodejs基于express实现文件上传的方法
Mar 19 NodeJs
Nodejs让异步变成同步的方法
Mar 02 NodeJs
Nodejs实现WebSocket代码实例
May 19 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学习 运算符与运算符优先级
2008/06/15 PHP
探讨如何把session存入数据库
2013/06/07 PHP
深入解析yii权限分级式访问控制的实现(非RBAC法)
2013/06/13 PHP
php function用法如何递归及return和echo区别
2014/03/07 PHP
php常用字符函数实例小结
2016/12/29 PHP
PHP+JQUERY操作JSON实例
2017/03/23 PHP
IE8下关于querySelectorAll()的问题
2010/05/13 Javascript
js 弹出框只弹一次(二次修改之后的)
2013/11/26 Javascript
JavaScript通过事件代理高亮显示表格行的方法
2015/05/27 Javascript
jQuery实现ToolTip元素定位显示功能示例
2016/11/23 Javascript
Javascript中字符串和数字的操作方法整理
2017/01/22 Javascript
从零开始学习Node.js系列教程一:http get和post用法分析
2017/04/13 Javascript
Vue2.0 UI框架ElementUI使用方法详解
2017/04/14 Javascript
jquery.validate.js 多个相同name的处理方式
2017/07/10 jQuery
JS中Safari浏览器中的Date
2017/07/17 Javascript
微信小程序自定义模态对话框实例详解
2017/08/16 Javascript
关于react-router/react-router-dom v4 history不能访问问题的解决
2018/01/08 Javascript
AngularJS中ng-options实现下拉列表的数据绑定方法
2018/08/13 Javascript
JavaScript惰性载入函数实例分析
2019/03/27 Javascript
微信小程序实现列表滚动头部吸顶的示例代码
2020/07/12 Javascript
vue+axios全局添加请求头和参数操作
2020/07/24 Javascript
Vue实现省市区三级联动
2020/12/27 Vue.js
python 输出所有大小写字母的方法
2019/01/02 Python
详解Python字典的操作
2019/03/04 Python
python3 常见解密加密算法实例分析【base64、MD5等】
2019/12/19 Python
Django ORM判断查询结果是否为空,判断django中的orm为空实例
2020/07/09 Python
Python包资源下载路径报404解决方案
2020/11/05 Python
python中_del_还原数据的方法
2020/12/09 Python
简单掌握CSS3将文字描边及填充文字颜色的方法
2016/03/07 HTML / CSS
CSS3 实现图形下落动画效果
2020/11/13 HTML / CSS
美津浓巴西官方网站:Mizuno巴西
2019/07/24 全球购物
经贸日语专业个人求职信
2013/12/13 职场文书
民政局副局长民主生活会个人整改措施
2014/10/04 职场文书
大学迎新生标语
2014/10/06 职场文书
教师个人培训总结
2015/02/11 职场文书
python 三边测量定位的实现代码
2021/04/22 Python