nightmare 是一个基于 electron 的自动化库(意思是说它自带浏览器),用于实现爬虫或自动化测试。相较于传统的爬虫框架(scrapy/pyspider),或者dom操作库(cheerio/jsdom),或者基于浏览器的自动化框架(selenium/phantomjs),他的优势在于提供了一个简洁有效 的编程模型。
来看官网给出的一个对比场景:
同样是实现一个向yahoo自动提交关键词并搜索的功能
1. PhantomJS实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
phantom . create ( function ( ph ) {
ph . createPage ( function ( page ) {
page . open ( 'http://yahoo.com' , function ( status ) {
page . evaluate ( function ( ) {
var el =
document . querySelector ( 'input[title="Search"]' ) ;
el . value = 'github nightmare' ;
} , function ( result ) {
page . evaluate ( function ( ) {
var el = document . querySelector ( '.searchsubmit' ) ;
var event = document . createEvent ( 'MouseEvent' ) ;
event . initEvent ( 'click' , true , false ) ;
el . dispatchEvent ( event ) ;
} , function ( result ) {
ph . exit ( ) ;
} ) ;
} ) ;
} ) ;
} ) ;
} ) ;
2. nightmare实现
yield Nightmare ( )
. goto ( 'http://yahoo.com' )
. type ( 'input[title="Search"]' , 'github nightmare' )
. click ( '.searchsubmit' ) ;
怎么玩
安装
涉及到下载并编译一个electron,你国网速下需耐心等待
openDevTools : {
mode : 'bottom' , // 开发者工具位置:right, bottom, undocked, detach
} ,
show : true , // 要不要显示浏览器
dock : true , // 要不要在Dock上显示图标
waitTimeout : 60000 , // .wait() 方法超时时长,单位:ms
executionTimeout : 86400000 , // .evaluate() 方法超时时长,单位:ms
实例化
import Nightmare from 'nightmare'
const nightmare = new Nightmare ( options )
简单介绍几个:
.goto(url[, headers])
跳转到url
.viewport(width, height)
浏览器窗口大小
.wait(selector)
等待某个dom元素出现
.click(selector)
点击某个dom元素
.type(selector[, text])
在某个dom元素中输入
.inject(type, file)
在页面上挂载 js/css 文件内容
.evaluate(fn[, arg1, arg2,...])
在客户端注入JS脚本并执行,从而实现electron模型下的C/S互动及数据交换
……
自动登录并轮询的例子
有那么一个网站(比如叫chagang.site),在我登录进去后,会不定时的查岗,需要点击一个按钮以证明没有离线,怎么用nightmare实现自动挂机呢?
大概分这么几步走:
先跳转到该网站
模拟输入帐号信息后点击submit
登录后等待主界面加载出现
在客户端起一个定时器,2秒一次轮询那个查岗按钮,发现就模拟点击
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
nightmare
. goto ( 'http://chagang.site/' )
. viewport ( 1024 , 768 )
. cookies . clearAll ( )
. type ( '#username' , '用户名' )
. type ( '#password' , '密码' )
. click ( 'input[type=submit]' )
. wait ( '#mainContent' )
. evaluate ( ( ) = > {
/* eslint-disable */
function handle ( ) {
// 一个叫inspector的button
var inspector = document . querySelector ( '#inspector' ) ;
if ( inspector && inspector . style . visibility === 'visible' ) {
inspector . click ( ) ;
}
}
setInterval ( handle , 2000 ) ;
/* eslint-enable */
} )
. evaluate ( ( ) = > document . title )
. then ( title = > console . log ( ` $ { title } = > 加载完成` ) )
. catch ( err = > console . error ( err ) )
好像也没有多难
小结
本文只涉及到API中的一小部分,宝贝都在文档 里。用 nightmare,就是希望借助这种简洁模型的梳理,相对愉悦的实现自动化交互(至于标题,终归是意义过剩的产物,请忽略他的招摇。
666
能不能过验证码~
过防重复提交token~
之前spam太多,才用的这招
谢谢分享
这玩意好~ 试了下,页面里的js,可以在代码里用~
nightmare
.goto(url1)
.cookies.get()
.then(function(cookies) {
……
})
.goto(url2)
求解:
goto(url2) 为什么 执行不了
如何才能继续执行goto(url2)
不好意思,是.cookie.set()
nightmare
.url(url)
.cookies.set(cookie)
.then(function() {
console.log(‘setCookie’);
callback();
})
no console setCookie
.then()和.catch()是整个执行链的最后步骤,goto不能放在他后面
大神有没有window系统的
额搞定了,就是弹出来窗口之后,不知道怎么合理利用啊 大神有没有进一步的运用的教程啊
额,这东西挺简单的,剩下就是组合运用各种API了
请问一下我按照你自动登录并轮询的例子代码,为什么evaluate里面的循环点击的代码好像没有运行
index.html
title
window.onload=function () {
var username=document.querySelector(‘#username’)
var password=document.querySelector(‘#password’)
var submit=document.querySelector(‘#submit’)
submit.onclick=function () {
if(username.value===’username’&& password.value===’123456′){
window.location.href=’/main.html’
}
}
}
main.html
title
#inspector{
display: block;
}
防止挂机按钮
window.onload=function () {
var inspector=document.querySelector(‘#inspector’);
inspector.onclick=function () {
this.style.display=’none’;
setTimeout(function () {
inspector.style.display=’block’;
},2000)
}
}
test.js
let Nightmare = require(‘nightmare’)
let nightmare = new Nightmare({
show: true,
openDevTools: {
mode: ‘detach’
},
})
nightmare
.goto(‘http://localhost:4001/’)
.viewport(1024, 768)
.wait(1000)
.type(‘#username’, ‘username’)
.type(‘#password’, ‘123456’)
.click(‘#submit’)
.wait(1000)
.wait(‘#mainContent’)
.evaluate(() => {
/* eslint-disable */
function handle() {
// 一个叫inspector的button
var inspector = document.querySelector(‘#inspector’);
if (inspector && inspector.style.display === ‘block’) {
inspector.click();
}
}
setInterval(handle, 1000);
/* eslint-enable */
})
.evaluate(() => document.title)
.then(title => console.log(
${title} => 加载完成
)).catch(err => console.error(err))
这个怎么实现对接数据库
用nodeJS的方法实现不了 会报错
具体指什么方法?