//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. 51nod 1215 数组的宽度

    若一个数在一段区间内作为最大值存在,那么答案应该加上这个数 若一个数在一段区间内作为最小值存在,那么答案应该减去这个数 所以我们利用单调栈,高效求出a[i]在哪个区间内作为最大/最小值存在,从而确定, ...

  2. Selenium Locating Elements

    Locating Elements Location Methods: find_element_by_id find_element_by_name find_element_by_xpath fi ...

  3. shiro执行原理

    一.架构 要学习如何使用Shiro必须先从它的架构谈起,作为一款安全框架Shiro的设计相当精妙.Shiro的应用不依赖任何容器,它也可以在JavaSE下使用.但是最常用的环境还是JavaEE.下面以 ...

  4. Beta 冲刺(3/7)

    目录 摘要 团队部分 个人部分 摘要 队名:小白吃 组长博客:hjj 作业博客:beta冲刺(3/7) 团队部分 后敬甲(组长) 过去两天完成了哪些任务 整理博客 ppt模板 接下来的计划 做好机动. ...

  5. Flask开发微电影网站(七)

    1.后台管理之电影管理 1.1 定义电影表单 在app的admin目录的forms.py文件中,定义电影表单 # 电影表单 class MovieForm(FlaskForm): title = St ...

  6. 初识Vue

    Vue.js介绍 Vue是一套用于构建用户界面的渐进式框架.与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用.Vue 的核心库只关注视图层,不仅易于上手,还便于与第三方库或既有项目整合.另 ...

  7. js中循环对比(for循环,foreach,for in,for of ,map)

    对空位的处理 for循环(不会忽略空位,标记undefined) var arr =[1,2,undefined,3,null,,7] for (let i=0;i<arr.length;i++ ...

  8. 错误: Error creating bean with name 'studentController': Unsatisfied dependency expressed through field 'studentServiceImpl';

    详细错误: 严重: Context initialization failed org.springframework.beans.factory.UnsatisfiedDependencyExcep ...

  9. js的逆向解析

    过程: 知道如何寻找登录的接口 知道如何确定js的位置 知道如何观察js的执行过程 知道js的执行方法 1. 确定网站的登录的接口登录的form表单中action对应的url地址通过抓包可以发现,在这 ...

  10. 11 个超棒的 jQuery 分步指引插件

    当一个网站或者一个Web应用推出新功能时,为了让用户了解你的站点(或应用)如何操作,往往都会在站点(应用)中添加一个分步指引的效果.然而这样的效果,对于不懂原生JS的同学来说,是件很头痛的事情. 下面 ...