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等模块直接获取,但对于动态页面,尽量先找数据接口,如果数据接口加密或者解析不出来,再去考虑用模拟浏览器,因为模拟浏览器会耗时间,当数据量一大,运行时间就会很长。
nodejs爬虫笔记(五)---利用nightmare模拟点击下一页的更多相关文章
- nodejs爬虫笔记(四)---利用nightmare解决加载更多问题
目标: 解决页面加载更多问题.笔记三中,我们只爬取到网页的部分信息,而点击加载更多后的页面内容是没有提取到的.开始我的想法是找到加载更多的数据接口(可参照:http://www.jianshu.com ...
- nodejs爬虫笔记(三)---爬取YouTube网站上的视频信息
思路:通过笔记(二)中代理的设置,已经可以对YouTube的信息进行爬取了,这几天想着爬取网站下的视频信息.通过分析YouTube,发现可以从订阅号入手,先选择几个订阅号,然后爬取订阅号里面的视频分类 ...
- nodejs爬虫笔记(二)---代理设置
node爬虫代理设置 最近想爬取YouTube上面的视频信息,利用nodejs爬虫笔记(一)的方法,代码和错误如下 var request = require('request'); var chee ...
- PYTHON 爬虫笔记十:利用selenium+PyQuery实现淘宝美食数据搜集并保存至MongeDB(实战项目三)
利用selenium+PyQuery实现淘宝美食数据搜集并保存至MongeDB 目标站点分析 淘宝页面信息很复杂的,含有各种请求参数和加密参数,如果直接请求或者分析Ajax请求的话会很繁琐.所以我们可 ...
- PYTHON 爬虫笔记八:利用Requests+正则表达式爬取猫眼电影top100(实战项目一)
利用Requests+正则表达式爬取猫眼电影top100 目标站点分析 流程框架 爬虫实战 使用requests库获取top100首页: import requests def get_one_pag ...
- nodejs爬虫笔记(一)---request与cheerio等模块的应用
目标:爬取慕课网里面一个教程的视频信息,并将其存入mysql数据库.以http://www.imooc.com/learn/857为例. 一.工具 1.安装nodejs:(操作系统环境:WiN 7 6 ...
- PYTHON 爬虫笔记九:利用Ajax+正则表达式+BeautifulSoup爬取今日头条街拍图集(实战项目二)
利用Ajax+正则表达式+BeautifulSoup爬取今日头条街拍图集 目标站点分析 今日头条这类的网站制作,从数据形式,CSS样式都是通过数据接口的样式来决定的,所以它的抓取方法和其他网页的抓取方 ...
- Python爬虫笔记【一】模拟用户访问之设置请求头 (1)
学习的课本为<python网络数据采集>,大部分代码来此此书. 网络爬虫爬取数据首先就是要有爬取的权限,没有爬取的权限再好的代码也不能运行.所以首先要伪装自己的爬虫,让爬虫不像爬虫而是像人 ...
- Python爬虫笔记【一】模拟用户访问之Tesseract-ocr验证码训练(5)
验证码处理之后就需要对处理的验证码进行识别训练,这里用Tesseract-ocr工具进行识别,用jTessBoxeditor进行训练生成模板. 一,对图片进行处理 利用上一篇代码对图片进行降噪处理,得 ...
随机推荐
- python将数据写入excel代码,python与office交互
# -*- coding: utf-8 -*- from smartframe.header import * import pymysql import json import importlib, ...
- Debian9 配置之旅
注:在安装的过程中,要选择网络镜像,不然要出大问题...(我选择了网易163的源) 注:下面的操作发生在我apt-get update,更新出现了错误,做的处理. _Stretch_ - Offici ...
- 迁移数据库数据到SQL Server 2017
概述 本篇我们将利用DMA一步一步实现SQL Server 的迁移.帮助大家理解现在的SQL Server与新版本的融合问题,同时需要我们做哪些操作来实现新版本的升级或者迁移. SQL Serve ...
- 【Sql】mySQL在windows环境启动
SQL的不同版本在Windows环境启动配置方法不同,此处仅介绍 5.7.20的配置方法: 1.登录mysql官网下载windows环境下的工具压缩包 http://dev.mysql.com/dow ...
- javascript 对象-13
对象 无序属性的集合,属性可以包含基本值.对象或者函数,简单理解为对象是若干属性的集合:我们常说的面向对象(oop)编程其实是指的一种编码的思想,简单理解为用对象来封装数据,利用封装.继承.多态对代码 ...
- 浅谈MySQL集群高可用架构
前言 高可用架构对于互联网服务基本是标配,无论是应用服务还是数据库服务都需要做到高可用.对于一个系统而言,可能包含很多模块,比如前端应用,缓存,数据库,搜索,消息队列等,每个模块都需要做到高可用,才能 ...
- in运算符(javascript)
in的用法,如x in y: 1.如果第二个运算数为对象,则in运算符用来检测第一个运算数是否是第二个运算数的属性名.是,返回true,否则返回false. 例: var obj = {x:1,y:2 ...
- JQuery常用知识点及示例
1.JQuery 名称解释 JQuery是封装了常用JS操作函数的一个库文件JQuery = Javascript + Query (查询)Jquery意思即指: 强大的DOM节点查询 2.官网:ht ...
- Oracle 数据库中在使用中文模糊查询时输入中文查询不到结果的解决方法
添加环境变量 变量名:NLS_LANG 变量值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK
- CCF系列之I’m stuck!(201312-5)
试题名称: I’m stuck! 时间限制: 1.0s 内存限制: 256.0MB 问题描述: 问题描述 给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', ...