稍加改动,手把手写一个acfun电影列表的爬虫-基于node

最近有空又重新看了vue2.0的文档,发现变动还是挺大的,多了虚拟dom,也像react有了对应JSX语法的render函数了,整个vue对象的生命周期也有了改动,而为了迎合2.0的标准版脚手架而不是每次都用2.0的简化版脚手架,我便决定开始慢慢的学习Node.js,其实之前也大概看过文档,但是总觉得没有需求,也不知从何下手,而现在个人发现语言和框架其实是为了解决问题而诞生了,那么学习其实也是在问题产生之后,需要解决问题而去主动学习。

我们最终的目的其实都是解决问题,这才是关键。

学习node的过程中,不带着需求学习更是茫然,看了文档却不知道去干什么~然而我突然很想写爬虫,总觉得很酷,所以毅然决定将这个需求带进node,用node来实现就好,又可以满足自己的需求又可以学习node,更是一举两得。

教程来自于一个简单的爬虫程序,是爬北大软件学院的新闻网的一些信息和图片,我已经收藏至我的收藏夹了,大家有兴趣可以看看,在这里我也把链接贴出来,由于是原创,所以不能随便转载
IT_石头的csdn博客-手把手教你做爬虫—基于NodeJs
坑爹的是,我爬了一次后,竟然就报超时了,刷新一下原网站,发现他们网站竟然崩了….有点逗了~

如果大家没看原作者的教程,那么请大家自行创建项目,去安装必要的东西
npm install request 这是node的第三方工具,不是自带的http的request,大家注意。

这里先声明一下,如果大家去爬的是完全同步请求的网站,记得要加载cheerio模块,它可以使你在node上实现jquery的方法,方便你去爬取对应标签,在原作者的教程中便是这个例子,大家自己去看看吧,A站由于电影列表有点特殊,是异步的get请求,所以这里做法是有区别的,如果按照原作者的思路走,你爬出来的电影列表一定是空的,因为请求地址已经不一样了。

好了,爬之前我们先看看A站电影列表的请求格式
A站电影列表其中一页

我们可以明确看到,请求是get的方式,而参数也很明显为channelId、sort、pageSize、pageNo,其中页码为pageNo控制,所以后续我们的get请求去改变pageNo即可,主机名为www.acfun.tv,请求地址为主机名底下的list/getlist,如果为post请求,那么我们根据node的文档将代码中改为http.request()的方式,methods方法为post即可,大家自己去研究吧,这里我就不说了~

好了,理解之后,于是我觉得去爬一些自己想爬的东西,所以就从经常上的网站开始吧,acfun的电影列表!show me my code

//我将其取名为acfun-movie.js
var http = require('http');//加载http模块
var fs = require('fs');    //加载文档流模块
var request = require('request');   //加载request模块

//初始页码
var page = 1;
//初始url,经过多次切换页码,我们确定只有pageNo是改变的,其他都是既定的
var url = 'http://www.acfun.tv/list/getlist?channelId=96&sort=0&pageSize=20&pageNo='+page;

//封装一层函数,我们优雅一点
function fetchPage(x){
    startRequest(x);
}

function startRequest(x){
    //利用http模块向服务器发起一次get请求
    http.get(x,function(res){
        var allData = '';  //用于存储请求网页的整个内容
        res.setEncoding('utf-8');
        //监听data事件,每次取一块数据
        res.on('data',function(chunk){
            allData += chunk;
        });

        //监听end事件,如果整个网页内容的html都获取完毕,就执行回调函数
        res.on('end',function(){
            //将取回的json格式字符串转为对象,并访问数据数组
            var resData = JSON.parse(allData).data.data;

            console.log('正在爬取第'+page+'页');
            saveContent(resData,page);//用于保存电影列表的内容
            saveImg(resData,page);    //用于保存电影列表的图片

            //下一篇的url
            var nextLink = 'http://www.acfun.tv/list/getlist?channelId=96&sort=0&pageSize=20&pageNo='+page;

            //亮点:递归函数控制爬虫的结束
            if(page<=10){
                fetchPage(nextLink);
            }
        });
    }).on('error',function(err){
        console.log(err);
    });
}

function saveContent(resData,page){
    var str = '';
    for(var i=0;i<resData.length;i++){
        //构造内容
        str += resData[i].title +'\r\n'+'链接:http://www.acfun.tv'+resData[i].link+'\r\n'+'up主'+resData[i].username+' 上传时间:'+resData[i].contributeTimeFormat+' 被观看次数:'+resData[i].viewCount+'\r\n\r\n'
    }
    //存储文本内容-参数为文件名,文件内容,文件格式,错误控制的回调函数
    fs.appendFile('./data/第'+page+'页电影列表.txt',str,'utf-8',function(err){
        if(err){
            console.log(err);
        }
    });
}

function saveImg(resData,page){
    for(var i=0;i<resData.length;i++){
        //此正则为中文取名,将名字'\'替换为'/'否则读取会被当做路径格式读取,现已注释,因为中文取名多容易发生错误
        // var img_title = resData[i].title;
        // img_title = img_title.replace(/\\/g,'/');
        //图片名,对应页码与排位
        var img_title = page+'-'+(i+1);
        //图片类型处理
        var img_type = resData[i].coverImage;
        img_type = img_type.slice(img_type.lastIndexOf('.'));
        //图片请求路径
        var img_src = resData[i].coverImage;
        console.log(img_src);

        //用request请求去验证图片超链接是否存在,这一步即使没有也可以运行,但最好利用head请求去 请求头部验证超链接是否存在与被修改,以防万一
        request.head(img_src,function(err,res,body){
            if(err){
                console.log(err)
            }
        });
        //request利用pipe流去存储图片,一定要写错误控制,否则会报错,未写错误控制
       console.log(img_title+img_type);
    request(img_src).pipe(fs.createWriteStream('./image/'+img_title+img_type)).on('error',function(err){
            if(err){
                console.log(err);
            }
        });
        console.log(img_title+'Done');
    }
}
//执行函数
fetchPage(url);

最后在项目文件夹下运行node acfun-movie.js 跑起来即可,这里就算完成了,希望大家不要用cv大法,毕竟只有自己打出来理解了才是自己的东西~
有一些图片的爬取会报错:no such file or directory,没有这个文件或这个目录,其实是A站的问题,因为。。。
这里写图片描述

如你所见,图片地址也是网络请求,这里我就没处理了,因为毕竟还是很少的~如果你有兴趣就自己去处理下吧~

补上完成图
存放内容与图片的文件夹

内容

内容示例

部分图片展示

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值