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学习笔记之FS文件模块
Jan 13 NodeJs
浅析nodejs实现Websocket的数据接收与发送
Nov 19 NodeJs
详解nodejs微信公众号开发——3.封装消息响应模块
Apr 10 NodeJs
解析NodeJS异步I/O的实现
Apr 13 NodeJs
nodejs后台集成ueditor富文本编辑器的实例
Jul 11 NodeJs
windows系统下更新nodejs版本的方案
Nov 24 NodeJs
nodejs实现连接mongodb数据库的方法示例
Mar 15 NodeJs
nodejs和react实现即时通讯简易聊天室功能
Aug 21 NodeJs
Nodejs中使用puppeteer控制浏览器中视频播放功能
Aug 26 NodeJs
nodejs语言实现验证码生成功能的示例代码
Oct 13 NodeJs
nodejs开发一个最简单的web服务器实例讲解
Jan 02 NodeJs
分享node.js实现简单登录注册的具体代码
Apr 26 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/01/10 PHP
PHP5中的时间相差8小时的解决办法
2008/03/28 PHP
PHP中使用Session配合Javascript实现文件上传进度条功能
2014/10/15 PHP
PHP实现对文件锁进行加锁、解锁操作的方法
2017/07/04 PHP
JQuery 写的个性导航菜单
2009/12/24 Javascript
5个javascript的数字格式化函数分享
2011/12/07 Javascript
js判断浏览器类型的方法
2013/08/07 Javascript
jquery获取URL中参数解决中文乱码问题的两种方法
2013/12/18 Javascript
JavaScript中的Web worker多线程API研究
2014/12/06 Javascript
node.js中的http.request.end方法使用说明
2014/12/10 Javascript
jquery常用的12个小功能
2016/07/22 Javascript
react性能优化达到最大化的方法 immutable.js使用的必要性
2017/03/09 Javascript
浅谈ES6新增的数组方法和对象
2017/08/08 Javascript
js实现移动端轮播图效果
2020/12/09 Javascript
JavaScript中重名的函数与对象示例详析
2017/09/28 Javascript
Node.js进阶之核心模块https入门
2018/05/23 Javascript
解决layui表格内文本超出隐藏的问题
2019/09/12 Javascript
npx create-react-app xxx创建项目报错的解决办法
2020/02/17 Javascript
JavaScript 实现下雪特效的示例代码
2020/09/09 Javascript
[01:06:43]完美世界DOTA2联赛PWL S3 PXG vs GXR 第二场 12.19
2020/12/24 DOTA
详解Python操作RabbitMQ服务器消息队列的远程结果返回
2016/06/30 Python
python中必要的名词解释
2019/11/20 Python
移动端HTML5开发神器之vconsole详解
2020/12/15 HTML / CSS
Roots加拿大官网:加拿大休闲服饰品牌
2016/10/24 全球购物
加拿大百叶窗和窗帘定制网站:Blinds
2017/01/30 全球购物
京东全球售:直邮香港,澳门,台湾,美国,澳大利亚等地区
2017/09/24 全球购物
zooplus德国:便宜地订购动物用品、动物饲料、动物食品
2020/05/06 全球购物
财务人员个人自荐信范文
2013/09/26 职场文书
会计自我鉴定范文
2013/10/06 职场文书
医学类个人求职信范文
2014/02/05 职场文书
电力安全事故反思
2014/04/27 职场文书
会计专业自荐信
2014/06/03 职场文书
观看建国大业观后感
2015/06/01 职场文书
再也不用花钱买漫画!Python爬取某漫画的脚本及源码
2021/06/09 Python
如何用Python搭建gRPC服务
2021/06/30 Python
Elasticsearch 配置详解
2022/04/19 Java/Android