//cnpm install superagent cheerio eventproxy fs path
var superagent = require('superagent');
var cheerio = require('cheerio');
var eventproxy = require('eventproxy');
var fs = require("fs");
var path = require("path");
var ep = new eventproxy(); //全局变量
var g = {
//抓取时间间隔
list_fetch_sec : 500,
//抓取页码数
list_fetch_num : 50,
//抓取失败待重试的数组
list_fail_url : [],
//最终获取的图片数组
list_href_arr : [],
//抓取的版块
pid:'douban_explore_ent',
//每个文件下的数据条数
file_data_num:30
}; get_article_list_url(); function get_list_url(){
var url_arr = [];
//控制抓取页码数
for(var i=0;i<g.list_fetch_num;i++){
var strat = i*30;
url_arr.push('https://www.douban.com/group/explore/ent?start='+strat);
}
return url_arr;
} //解析列表页dom
function parseList(all_arr){
//遍历
all_arr.forEach(function (item) {
var itemUrl = item[0];
var itemHtml = item[1]; console.log('列表页抓取完成'); var $ = cheerio.load(itemHtml);
var a_dom = $('#content .channel-item .bd h3 a'); a_dom.each(function(){
var href = $(this).attr('href');
console.log(href);
g.list_href_arr.push(href);
});
});
} //解析详情页dom
function praseDetail(all_arr){
var text_arr = [];
all_arr.forEach(function (item) {
var itemUrl = item[0];
var itemHtml = item[1];
var group_no = item[2];
if(itemHtml){
//decodeEntities 是否解码实体
var $ = cheerio.load(itemHtml,{decodeEntities: false});
var content_jq = $('#content .topic-doc .topic-content');
var title_jq = $('#content h1');
try{
var first_floor = content_jq.html();
var title = title_jq.text();
var data = {
content:first_floor,
title:title,
url:itemUrl
};
text_arr.push(data);
}catch(msg){
console.log('error');
}
}
});
return text_arr;
} //获取帖子列表
//feeling
function get_article_list_url(){
var url_arr = get_list_url(); url_arr.forEach(function (url,index) {
var _index = index+1;
fetch_op(url,_index,g.list_fetch_sec,'list_parse','');
}); ep.after('list_parse', url_arr.length, function (all_arr) {
parseList(all_arr);
console.log('开始抓取详情页');
get_article_detail();
});
} //获取帖子详情
function get_article_detail(){
//分割数组
var obj = {};
g.list_href_arr.forEach(function (url,index) {
var _group = parseInt(index/g.file_data_num)+1;
//没有则新建数组
if(!obj[_group]){
obj[_group] = [];
}
obj[_group].push(url);
}); console.log(obj); var group_no;
for(group_no in obj){
var group_data = obj[group_no];
var len = group_data.length;
//设置计数器
ep_after(group_no,len); //每组再遍历
var j;
var count = 0;
for(j in group_data){
count++;
var url = group_data[j];
var _index = count;
fetch_op(url,_index,g.list_fetch_sec,'detail_parse_'+group_no,group_no);
}
}
} function ep_after(_group,len){
//计数器作用 当emit的detail_parse达到指定的数量时出发回调
ep.after('detail_parse_'+_group, len, function (all_arr) {
console.log('详情页第['+_group+']组抓取完成'); var text_arr = praseDetail(all_arr); if(text_arr.length){
//如果目录不存在 同步创建目录
var dir_path_name = get_dir_path_name(g.pid);
if (!fs.existsSync(dir_path_name)) {
console.log('新建目录: '+dir_path_name);
fs.mkdirSync(dir_path_name);
} console.log('saveing '+'详情页第['+_group+']组');
var save_data = {data:text_arr};
var path_name = get_file_path_name(g.pid,_group);
fs.writeFile(path_name, JSON.stringify(save_data), function (err) {
if (err) throw err;
console.log('save done!');
});
}
});
} function get_file_path_name(dirname,no){
var filename = dirname+'_'+no+'.js';
return path.join(__dirname,'data',dirname,filename);
} function get_dir_path_name(dirname){
return path.join(__dirname,'data',dirname);
} function fetch_op(url,i,sec,emit_name,group_no){
setTimeout(function(){
superagent.get(url)
.end(function (err, res) {
if(res){
console.log('抓取 第['+group_no+']组 ' + url + ' 成功');
ep.emit(emit_name, [url,res.text,group_no]);
}else{
ep.emit(emit_name, [url,'',group_no]);
console.log('抓取 第['+group_no+']组 ' + url + ' 失败');
}
});
},i*sec);
}

注意:以上代码请仅用于学习用途,切勿用于生产环境或者其他非法用途,否则后果请自行承担

superagent 是一个轻量的,渐进式的ajax api,可读性好,学习曲线低,内部依赖nodejs原生的请求api

cheerio 用于解析dom,用法与jquery类似

eventproxy 并发控制(计数器功能)

功能:爬取豆瓣的某版块列表页中的详情的内容,自动创建文件夹并写入文件中存储,可供接口调用。

代码解读:

执行get_article_list_url方法获取列表的url存进g.list_href_arr中,在执行完成的计数器回调中调用get_article_detail方法,该方法首先根据g.file_data_num对g.list_href_arr的url进行分组,
分完组后根据组数控制请求间隔,在执行完成的计数器回调中新建目录,将抓取回来的数据写入文件。
可直接供前端做接口使用。

nodejs 使用superagent+cheerio+eventproxy爬取豆瓣帖子的更多相关文章

  1. 第一个nodejs爬虫:爬取豆瓣电影图片

    第一个nodejs爬虫:爬取豆瓣电影图片存入本地: 首先在命令行下 npm install request cheerio express -save; 代码: var http = require( ...

  2. Node.js爬取豆瓣数据

    一直自以为自己vue还可以,一直自以为webpack还可以,今天在慕课逛node的时候,才发现,自己还差的很远.众所周知,vue-cli基于webpack,而webpack基于node,对node不了 ...

  3. urllib+BeautifulSoup无登录模式爬取豆瓣电影Top250

    对于简单的爬虫任务,尤其对于初学者,urllib+BeautifulSoup足以满足大部分的任务. 1.urllib是Python3自带的库,不需要安装,但是BeautifulSoup却是需要安装的. ...

  4. python2.7爬取豆瓣电影top250并写入到TXT,Excel,MySQL数据库

    python2.7爬取豆瓣电影top250并分别写入到TXT,Excel,MySQL数据库 1.任务 爬取豆瓣电影top250 以txt文件保存 以Excel文档保存 将数据录入数据库 2.分析 电影 ...

  5. python定时器爬取豆瓣音乐Top榜歌名

    python定时器爬取豆瓣音乐Top榜歌名 作者:vpoet mail:vpoet_sir@163.com 注:这些小demo都是前段时间为了学python写的,现在贴出来纯粹是为了和大家分享一下 # ...

  6. Scrapy 通过登录的方式爬取豆瓣影评数据

    Scrapy 通过登录的方式爬取豆瓣影评数据 爬虫 Scrapy 豆瓣 Fly 由于需要爬取影评数据在来做分析,就选择了豆瓣影评来抓取数据,工具使用的是Scrapy工具来实现.scrapy工具使用起来 ...

  7. Python爬取豆瓣音乐存储MongoDB数据库(Python爬虫实战1)

    1.  爬虫设计的技术 1)数据获取,通过http获取网站的数据,如urllib,urllib2,requests等模块: 2)数据提取,将web站点所获取的数据进行处理,获取所需要的数据,常使用的技 ...

  8. scrapy爬虫框架教程(二)-- 爬取豆瓣电影TOP250

    scrapy爬虫框架教程(二)-- 爬取豆瓣电影TOP250 前言 经过上一篇教程我们已经大致了解了Scrapy的基本情况,并写了一个简单的小demo.这次我会以爬取豆瓣电影TOP250为例进一步为大 ...

  9. scrapy爬取豆瓣电影top250

    # -*- coding: utf-8 -*- # scrapy爬取豆瓣电影top250 import scrapy from douban.items import DoubanItem class ...

随机推荐

  1. ceph简单用户管理

    列出所有用户 ceph auth list 获取指定用户 ceph auth get client.admin 新增用户并输出密钥环 ceph auth get-or-create client.ge ...

  2. ActiveMQ的Destination高级特性

    1.    Composite Destinations  组合目的地 组合队列Composite Destinations : 允许用一个虚拟的destination代表多个destinations ...

  3. Git入门——本地版本库操作

    作为一个一直用SVN的家伙,深深地感到了自己在版本控制工具上的落伍.... 首先必须强调的是: Git与Github不是一回事. Git是目前世界上最先进的分布式版本控制系统,于2005年被linux ...

  4. js-检测字符串出现次数最多,并返回

    function validateStr(val){ let obj = {}; let maxNum = -1; let maxStr; for(let i=0;i<val.length;i+ ...

  5. Java的家庭记账本程序(L)

    日期:2019.3.13 博客期:044 星期三 整理了两天,我终于也是把微信小程序平台的记账本软件完全开发出来了,并将我的微信账号与GitHub账号完成了绑定,那么我就先展示一部分作品,还有一部分代 ...

  6. CAP分布式事务 学习及简单demo

    完全参考 github的指导 demo地址, Pub使用 efcore , Sub 使用 dapper, mysql数据库 https://files.cnblogs.com/files/xtxtx/ ...

  7. UOJ#407. 【IOI2018】狼人 Kruskal,kruskal重构树,主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ407.html 题解 套路啊. 先按照两个节点顺序各搞一个kruskal重构树,然后问题转化成两棵krus ...

  8. SSH项目需要的所有架包

    原地址:https://blog.csdn.net/qq_35816104/article/details/54346182   SSH框架:struts2 hibernate spring 该三大框 ...

  9. python基础篇_004_装饰器函数

    python装饰器函数 1.装饰器函数引导 功能:计算函数执行时长 import time """ 方式一: 函数首位添加时间,差值就是函数执行时间 缺点:每个函数都要加 ...

  10. Codeforces 811C Vladik and Memorable Trip (区间异或最大值) (线性DP)

    <题目链接> 题目大意: 给你n个数,现在让你选一些区间出来,对于每个区间中的每一种数,全部都只能出现在这个区间. 每个区间的价值为该区间不同的数的异或值之和,现在问你这n个数最大的价值是 ...