nodejs爬虫笔记(五)---利用nightmare模拟点击下一页

目标

  以腾讯滚动新闻为例,利用nightmare模拟点击下一页,爬取所有页面的信息。首先得感谢node社区godghdai的帮助,开始接触不太熟悉nightmare,感觉很高大上,自己写代码的时候问题也很多,多亏大神的指点。

一、选择模拟的原因

  腾讯滚动新闻,是每六十秒更新一次,而且有下一页。要是直接获取页面的话得一页一页的获取,不太方便,又想到了找数据接口,然后通过请求得到数据,结果腾讯新闻的数据接口是加密的,这种想法又泡汤了。因而想到笔记(四)中模拟加载更多的模块,看利用nightmare这个模块模拟点击下一页,是不是就可以获取全部新闻的信息了呢。

二、分析页面

  打开腾讯滚动新闻页面,通过浏览器点击检查,选择页码部分内容(如图),此时是第一页,上一页的类名是"na",下一页的类名是是"f12",再点击第二页的时候会发现上一页和下一页的类名都是"f12",要选择下一页,可以利用Jquery选择器中过滤元素的方法,如:$(‘#pageArea .f12:contains("下一页")‘),这样就可以选择点击下一页了。从下图可以看到页面去还有页面总数,因此可以获取页面总数,然后通过页面总数做一个点击的判断,直到点击到最后一页。再点击到最后一页,会发现下一页的类名会变成"na",因此,我们也可以通过下一页的类名变化判断是否点击到了最后一页。

                

三、思路一(利用总页数)

  1、在nightmare的wait方法里面等待页面加载完成。

  2、之后获取总页数,没点击一次,总页数就减一,直到最后一页,点击完成,wait方法才返回true。

  在文件目录下新建qqnightmare.js(需要安装相关模块),编辑如下代码:

var Nightmare = require(‘nightmare‘);
var nightmare = Nightmare({
	show: true//显示electron窗口
});

nightmare
	//加载页面
	.goto(‘http://roll.news.qq.com/‘)
	.wait(function() {
        return document.querySelectorAll("#artContainer li").length>0;//通过新闻列表的长度,来判断页面是否加载完成
    })
	.inject(‘js‘,‘jquery.min.js‘)//插入jquery
	.wait(function(){
		if(window.qqNews === undefined){              //定义变量
			window.qqNews={
				page :$("#totalPage").val();,
				arr : []
			};
			if(qqNews.page!==1){
	  			$(‘#artContainer li‘).each(function(){
			  		var title = $(this).find(‘a‘).text();
			  		qqNews.arr.push(title);
	  			});
	  			$(‘#pageArea .f12:contains("下一页")‘).click();
	  			qqNews.page -= 1;
	  			return false;
	  		}
	  		if(qqNews.page===1){
	  			$(‘#artContainer li‘).each(function(){
			  		var title = $(this).find(‘a‘).text();
			  		qqNews.arr.push(title);
	  			});
	  			return true;
	  		}
		}
		return false;
	})
	.evaluate(function(){
		return qqNews.arr;
	})
	.end()
	.then(function(res){
	  console.log(res,res.length);
	})
	.catch(function (error) {
	  console.error(‘failed:‘, error);
	});

  在后台打开文件夹,运行node qqnightmare ,会发现wait方法等待超时。检查代码后发现wait方法一直没有返回true,因为每次判断qqNews.page!==1,会返回false,再次调用又会重新定义一个变量,因此一直会返回false,根本不会返回true。是不是可以添加一个wait用来定义变量,改写代码如下:

var Nightmare = require(‘nightmare‘);
var nightmare = Nightmare({
	show: true//显示electron窗口
	// waitTimeout : 5000
});

nightmare
	//加载页面
	.goto(‘http://roll.news.qq.com/‘)
	.wait(function() {
        return document.querySelectorAll("#artContainer li").length>0;
    })
    .inject(‘js‘,‘jquery.min.js‘)
    .wait(function(){
        window.qqNews=[];
        page = $("#totalPage").val();
        return true;
    })
	.wait(function(){

		if(page!==1){
  			$(‘#artContainer li‘).each(function(){
		  		var title = $(this).find(‘a‘).text();
		  		qqNews.push(title);
  			});
  			$(‘#pageArea .f12:contains("下一页")‘).click();
  			page -= 1;
  			return false;
  		}
  		if(page===1){
  			$(‘#artContainer li‘).each(function(){
		  		var title = $(this).find(‘a‘).text();
		  		qqNews.push(title);
  			});
  			return true;
  		}	

		return false;
	})
	.evaluate(function(){
		return qqNews;
	})
	.end()
	.then(function(res){
	  console.log(res,res.length);
	})
	.catch(function (error) {
	  console.error(‘failed:‘, error);
	});

  再点击运行,会发现所有的新闻都打印出来了。

四、思路二(根据下一页类名判断)

var Nightmare = require(‘nightmare‘);
var nightmare = Nightmare({
    show: true //显示electron窗口
});
nightmare
    .goto(‘http://roll.news.qq.com/‘)
    .wait(function() {
        return !document.querySelector(".loading");
    })
    .wait(function() {
        window._$qqNews = [];
        return true;
    })
    .wait(function() {

        //如果显示正在加载中……
        if (document.querySelector(".loading")) return false;

        var newslist = document.querySelectorAll("#artContainer li a");
        for (var i = 0; i < newslist.length; i++) {
            _$qqNews.push({
                title: newslist[i].childNodes[0].data,
                href: newslist[i].href
            });
        }

        var next_page_button = document.querySelector("#pageArea .f12:last-child");
        if (next_page_button) {
            next_page_button.click();
            return false;
        }
        return true;

    })
    .evaluate(function() {
        return _$qqNews;
    })
    .end()
    .then(function(res) {
        console.log(res[res.length-1], res.length);
    })
    .catch(function(error) {
        console.error(‘failed:‘, error);
    });

  运行后会发现所有新闻也都打印到后台了,另外大神还给出了另外一种方法,自己不太懂,也就不多说了,就放这存一下吧。

五、通过js文件获取全部新闻信息

  点击检查页面,会发现相应的js内容如下图,再点击sources查看js,会发现js文件夹下有qq.js文件,这个文件里面包含了所有的方法等信息。

大神给的代码:

var Nightmare = require(‘nightmare‘);
var nightmare = Nightmare({
    show: true,
    pollInterval: 1000
});

nightmare
    .goto(‘http://roll.news.qq.com/‘)
    .wait(function() {
        return document.querySelectorAll("#artContainer li").length>0;
    })
    .wait(function() {

        if (window._$qqNews == undefined) {

            window._$qqNews = {
                total: 0,
                page: 0,
                items: []
            }

            //停止自动刷新
            AutoRefresh();
            _$qqNews.total = qq.$("totalPage").value;

            G.showArtList = function(responseText) {
                try {
                    eval("var json = " + responseText);
                    if (json.response.code == "0") {
                        qq.$("artContainer").innerHTML = json.data.article_info;

                        //
                        var newslist = document.querySelectorAll("#artContainer li a");
                        for (var i = 0; i < newslist.length; i++) {

                            _$qqNews.items.push({
                                title: newslist[i].childNodes[0].data,
                                href: newslist[i].href
                            });
                        }

                        qq.$("totalPage").value = json.data.count;

                        if (_$qqNews.total > 1) {
                            _$qqNews.total -= 1;
                            nextPage();
                        }

                    } else if (json.response.code == "2") {
                        qq.$("totalPage").value = 1;
                        G.gotoPage(1);
                        qq.$("artContainer").innerHTML = ‘<div class="article-tips">该日期没有文章!</div>‘;
                    } else {
                        qq.$("totalPage").value = 1;
                        G.gotoPage(1);
                        qq.$("artContainer").innerHTML = ‘<div class="article-tips">文章加载失败!</div>‘;
                    }
                } catch (e) {}
            }

            //加载第1页
            Refresh();

            return false;
        }

        if (_$qqNews.total == 1)
            return true;

        return false;

    }).evaluate(function() {

        return _$qqNews.items;
    })
    .end()
    .then(function(result) {
        console.log(result, result.length)
    }).catch(function(error) {
        console.log(‘错误是:‘ + error);
    })

 运行之后,会发现运行时间相对来讲要比前面两种快一些。 

六、总结

  通过一段时间的爬虫,发现静态页面可以直接通过request和cheerio等模块直接获取,但对于动态页面,尽量先找数据接口,如果数据接口加密或者解析不出来,再去考虑用模拟浏览器,因为模拟浏览器会耗时间,当数据量一大,运行时间就会很长。

时间: 2024-11-11 11:51:30

nodejs爬虫笔记(五)---利用nightmare模拟点击下一页的相关文章

nodejs爬虫笔记(二)

node爬虫代理设置 最近想爬取YouTube上面的视频信息,利用nodejs爬虫笔记(一)的方法,代码和错误如下 var request = require('request'); var cheerio = require('cheerio');**** var url = 'https://www.youtube.com '; function crawler(url,callback){ var list = []; request(url,function(err,res){ if(e

nodejs 爬虫笔记

目标:爬取慕课网里面一个教程的视频信息,并将其存入mysql数据库.以http://www.imooc.com/learn/857为例. 一.工具 1.安装nodejs:(操作系统环境:WiN 7 64位)  在Windows环境下安装相对简单(ps:其他版本我也不太清楚,可以问度娘) http://nodejs.org/download/ 链接中下载对应操作系统安装文件(安装最新版本就行) 按照提示,一路下一步直到安装成功后,在默认安装路径下可以看到(C:\Program Files\node

nodejs爬虫笔记(三)

思路:通过笔记(二)中代理的设置,已经可以对YouTube的信息进行爬取了,这几天想着爬取网站下的视频信息.通过分析YouTube,可以从订阅号入手,先选择几个订阅号,然后爬取订阅号里面的视频分类,之后进入到每个分类下的视频列表,最后在具体到每一个视频,获取需要的信息.以订阅号YouTube 电影为例. 一.爬取YouTube 电影里面的视频分类列表 打开订阅号,我们可以发现订阅号下有许多视频分类如下图所示,接下来可以解析该订阅号信息,把视频分类的URL和名称爬取下来. 接下来我们通过浏览器点击

nodejs学习笔记&lt;五&gt;npm使用

NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题. 以下是几种常见使用场景: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用. 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用. npm是集成在node.js一并安装的.所以可以直接在命令行通过npm -v命令查看当前npm的版本号. npm的升级可以通过npm命令. npm install npm -g(仅用于window

爬虫——模拟点击动态页面

动态页面的模拟点击: 以斗鱼直播为例:http://www.douyu.com/directory/all 爬取每页的房间名.直播类型.主播名称.在线人数等数据,然后模拟点击下一页,继续爬取 #!/usr/bin/python3 # -*- conding:utf-8 -*- __author__ = 'mayi' """ 动态页面的模拟点击: 模拟点击斗鱼直播:http://www.douyu.com/directory/all 爬取每页房间名.直播类型.主播名称.在线人数

python爬虫入门(五)Selenium模拟用户操作

爬虫(Spider),反爬虫(Anti-Spider),反反爬虫(Anti-Anti-Spider) 之间恢宏壮阔的斗争... 小莫想要某站上所有的电影,写了标准的爬虫(基于HttpClient库),不断地遍历某站的电影列表页面,根据 Html 分析电影名字存进自己的数据库. 这个站点的运维小黎发现某个时间段请求量陡增,分析日志发现都是 IP(xxx.xxx.xxx.xxx)这个用户,并且 user-agent 还是 Python-urllib/2.7 ,基于这两点判断非人类后直接在服务器上封杀

[python]利用selenium模拟用户操作抓取天猫评论数据

准备: python3.5 安装selenium包 第一种方法: cmd里输pip install selenium,但是经常报错 第二种方法: 下载安装包-cmd进入解压路径-python setup.py install-报错permission denied-右键安全更改报错文件夹权限为完全控制-再次安装成功unknown error: unable to discover open pages-下载chromedriver放在环境变量目录下测试自动打开百度时提示"您使用的是不受支持的命令

python爬虫第五天

第五天: Selenium Selenium是一个Web的自动化测试工具,最初是为网站自动化测试而开发的,类型像我们玩游戏用的按键精灵,可以按指定的命令自动操作,不同是Selenium 可以直接运行在浏览器上,它支持所有主流的浏览器(包括PhantomJS这些无界面的浏览器). 安装 这里推荐使用pip安装,执行如下命令即可: pip install selenium 验证安装 进入python命令交互模式,导入selenium包,如果没有报错,则证明安装成功. Import selenium

记一次nodejs 爬虫(利用递归循环nightmare)

记一次nodejs 爬虫(利用递归循环nightmare) 新手,欢迎交流 目标网站 这里的网址很有规律,方便我们获取图书列表的url nightmare几个主要的api 具体参考:http://www.manongjc.com/detail/8-roxmpabfhewimht.html .goto(url,options) url:目标网站 options:伪造头部信息 .wait(callback[selector]) 这个方法会重复调用,直到 return true, 可以传入选择器,如: